NHibernate系列文章十一:NHibernate并发控制
摘要
在同一时刻数据访问量和更新次数比较大的系统中,产生了数据的并发访问问题。并发访问使得在这样的环境中,所有用户(程序、实际用户、进程、线程等)的操作不产生负面问题。
如果不使用并发,在两个用户同时写同一条数据的时候,最后结果是不确定的。不使用并发的时候两个客户同时删除同一条数据,将产生异常终止程序。
并发控制方式有两种:悲观并发控制和乐观并发控制,NHibernate使用乐观并发控制。这篇文章首先介绍这两种策略,然后详细介绍NHibernate的乐观并发控制。
1. 悲观并发控制和乐观并发控制
悲观并发控制
悲观并发控制是基于控制锁的一种并发控制,在对一条数据的所有用户操作之前都加一把并发锁。在一个用户要对一条数据进行修改之前给这条记录加一把排他锁,其他用户要修改此记录必须等待,只有在前一个用户更新完该记录之后,或者主动释放锁,这个锁才解开,其他用户才能够重新得到这把锁,更新这条记录。
因为读者和写者阻塞,写者和写者阻塞,所以他可能产生数据争用冲突,而且效率一般比较低。
悲观并发控制主要用于数据争用比较激烈的环境,而且锁的成本低于数据回滚的成本的情况下。
乐观并发控制
乐观并发控制是基于版本号或者时间戳的一种并发控制。对所有需要进行并发控制的数据上加一个版本号或者时间戳的字段或者属性,当产生争用冲突的时候,检验数据版本是否最新。如果不是最新,则回滚当前用户对数据的写操作。
乐观并发控制主要用于数据争用不那么激烈的环境,偶尔数据争用时回滚事务的成本低于锁的成本的情况下。
2. NHibernate的乐观并发控制
NHibernate默认使用乐观并发控制,默认给所有NHibernate实体类对象添加了一个“程序看不见”的Version属性,通过持久化对象的版本进行并发控制。
但是我们可以通过给实体关系映射文件中添加并发控制字段(version或timestamp)来显示地观察NHibernate是怎样进行乐观并发控制的。
以version为例:
<version name="属性名" column="列名" type=".Net数据类型" unsaved-value="对象临时态时主键值"/>
- name为必填属性
- colonm名称如果和属性名相同时可以省略
- type类型是.Net基本类型时可以省略
- type类型是.Net基本数据类型时,NHibernate能够自动推断主键属性默认值,因此可以省略unsaved-value
timestamp是可以理解为不够强的版本控制,以对象的最后更新的时间戳为当前最新版本。
程序演示
给Customer表添加字段Version,类型为int,不为空,默认值为1。

数据库数据的初始值

修改Customer.hbm.xml文件,添加version节点
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernateDemoApp" namespace="NHibernateDemoApp">
<class name="Customer" table="Customer">
<id name="Id">
<generator class="native"/>
</id>
<version name="Version"/>
<property name="FirstName" not-null="true"/>
<property name="LastName" not-null ="true"/>
<property name="AverageRating"/>
<property name="Points"/>
<property name="HasGoldStatus"/>
<property name="MemberSince"/>
<property name="CreditRating" type="CustomerCreditRating"/>
<property name="Street"/>
<property name="City"/>
<property name="Province"/>
<property name="Country"/>
</class>
</hibernate-mapping>
修改Customer类,添加Version属性
public class Customer
{
public virtual int Id { get; set; }
public virtual int Version { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual double AverageRating { get; set; }
public virtual int Points { get; set; }
public virtual bool HasGoldStatus { get; set; }
public virtual DateTime MemberSince { get; set; }
public virtual CustomerCreditRating CreditRating { get; set; }
public virtual string Street { get; set; }
public virtual string City { get; set; }
public virtual string Province { get; set; }
public virtual string Country { get; set; }
}
1)修改操作的乐观并发控制
修改Main函数
static void Main(string[] args)
{
HibernatingRhinos.Profiler.Appender.NHibernate.NHibernateProfiler.Initialize(); using (var session = SessionFactory.OpenSession())
{
var customer1 = session.Get<Customer>();
var customer2 = session.Get<Customer>(); customer1.LastName = "Chen";
customer2.LastName = "Liu";
session.Update(customer1);
session.Flush();
session.Update(customer2);
session.Flush();
} Console.WriteLine("Completed");
Console.ReadLine();
}
打开NHibernate Profile,清空Session,执行程序,得到结果。

看到虽然调用了两次Session.Update和Session.Flush,但是实际上只执行了一次Update语句。只有最后一次Update被执行,第一次Update操作被自动回滚了。生成的Update语句中的查询条件增加了Version=1这个条件。
执行后数据库记录:

2)删除操作的乐观并发控制
修改Main函数
static void Main(string[] args)
{
HibernatingRhinos.Profiler.Appender.NHibernate.NHibernateProfiler.Initialize(); using (var session = SessionFactory.OpenSession())
{
var customer1 = session.Get<Customer>();
var customer2 = session.Get<Customer>(); session.Delete(customer1);
session.Delete(customer2);
session.Flush();
}
Console.WriteLine("Completed");
Console.ReadLine();
}
这里只用了一次Session.Flush,因为在第一次Flush后,持久化对象从持久化对象集合中删除了,此后调用Session.Delete方法会因为在持久化对象集合中找不到该对象而抛出异常。
清空NHibernate Profile的Session,执行程序,得到结果.

虽然调用了两次Session.Delete,但是只执行了一次Delete的SQL语句。
Id等于3的记录被删除了

NHibernate系列文章十一:NHibernate并发控制的更多相关文章
- NHibernate系列文章二十一:延迟加载
摘要 NHibernate的延迟加载机制是很重要的内容.通过关系映射将数据库表之间的关系映射成对象之间的关系,如果没有延迟加载机制,从主表的一个对象的查询将直接查询出所有与该对象关联的其他对象,如果关 ...
- NHibernate系列文章一:NHibernate介绍
摘要 NHibernate是一个成熟的开源的面向对象的.net映射框架.大量的实际项目中正在使用该框架.他是建立在ADO.Net基础之上.目前的版本是NHibernate 4.0.4.本系列文章都是基 ...
- NHibernate系列文章目录
第一章:NHibernate基础 NHibernate介绍 第一个NHibernate工程 简单的增删改查询 运行时监控 NHibernate配置 数据类型映射 Get/Load方法 NHiberna ...
- NHibernate系列文章二十七:NHibernate Mapping之Fluent Mapping基础(附程序下载)
摘要 从这一节起,介绍NHibernate Mapping的内容.前面文章都是使用的NHibernate XML Mapping.NHibernate XML Mapping是NHibernate最早 ...
- NHibernate系列文章二十三:NHibernate查询之Criteria查询(附程序下载)
摘要 上一篇文章介绍了NHibernate HQL,他的缺点是不能够在编译时发现问题.如果数据库表结构有改动引起了实体关系映射的类有改动,要同时修改这些HQL字符串.这篇文章介绍NHibernate面 ...
- NHibernate系列文章十五:NHibernate组件
摘要 前面文章介绍了NHibernate对简单.net数据类型的映射对照表.NHibernate也可以映射复杂数据类型,这里介绍通过组件映射NHibernate值对象. 1. NHibernate引用 ...
- NHibernate系列文章九:NHibernate对象二级缓存上
摘要 NHibernate的二级缓存由SessionFactory管理,由所有Session共享. NHibernate缓存读取顺序: 首先从一级缓存中读取,如果一级缓存对象存在,则读取一级缓存对象并 ...
- NHibernate系列文章十八:NHibernate关系之一对多(附程序下载)
摘要 这篇文章介绍NHibernate最实用的内容:关系映射. NHibernate的关系映射方式有三种: Set:无序对象集合,集合中每一个元素不能重复. List:有序对象集合,集合中的元素可以重 ...
- NHibernate系列文章十:NHibernate对象二级缓存下
摘要 上一节对NHibernate二级缓存做了简单介绍,NHibernate二级缓存是由SessionFactory管理的,所有Session共享.这一节介绍二级缓存其他两个方面:二级缓存查询和二级缓 ...
随机推荐
- 关于relative和absolute的总结
对于定位这个性质我原理上来说自己是明白的,但是在实践的过程中,总会出现各种稀奇古怪的情况,加relative或是absolute就可以解决,但是遇到这些情况总是不明白为什么!!!难道是脑容量太小的原因 ...
- php轮流排序,每隔一定的时间轮流进行位置排序,轮询的排行榜:function dataPollingInterval()
/* * @名称: php ,对数组每隔一定的时间(自设定时间)来轮流进行位置排序,轮询的排行榜. 精确到指定的秒 或 分钟 或 小时 或 天 ,对数据列表进行轮排. * @参数: (array)$l ...
- 让android项目支持boost 支持c++11
在Application.mk 里增加-D__GLIBC__ 让项目支持boost 增加 -std=c++11 让项目支持c++11 (3.x的cocos本身已经支持了的) 看起来这样: APP_S ...
- meta-analysis 到底是什么个意思类?
背景 科学研究应建立于许多实验结果的重复之上,除了少数新发现外,单个实验结果很难对科学的发展作出极为显著的贡献.所以为了阐明某一主题,在许多科学领域有众多研究者在对不同的实验对象或对同一对象在不同的实 ...
- Fragment实现延迟加载
import android.support.v4.app.Fragment; public abstract class BaseFragment extends Fragment { /** Fr ...
- Django中ImageField的使用
http://blog.csdn.net/u013690521/article/details/38777213 from django.db import models from django.co ...
- lua加载动态库缺乏相应的系统库
错误信息: 使用lua测试lm2动态库时,加载时出现如下错误 jfyuan@jfy11-B85M-D2V:~/temp/service/soft/code/ginger_resty/cores/lm2 ...
- Squid代理服务器的安装与配置
一.简介 代理服务器英文全称是Proxy Server,其功能就是代理网络用户去取得网络信息. Squid是一个缓存Internet 数据的软件,其接收用户的下载申请,并自动处理所下载的数据.当一个用 ...
- Servlet与JSP的区别
一.基本概念 1.1 Servlet Servlet是一种服务器端的Java应用程序,具有独立于平台和协议的特性,可以生成动态的Web页面.它担当客户请求(Web浏览器或其他HTTP客户程序)与服务器 ...
- 打印心形---print 的基础使用
#!/bin/usr/env python#coding=utf-8'''用学习到的print语句,完成如下图形的打印工作打印心形'''print " *** *** "print ...