NHibernate之旅(7):初探NHibernate中的并发控制

本节内容

什么是并发控制?悲观并发控制(Pessimistic Concurrency)乐观并发控制(Optimistic Concurrency)什么是并发控制?

当许多人试图同时修改数据库中的数据时,,必须实现一个控制系统,使一个人所做的修改不会对他人所做的修改产生负面影响。这称为并发控制。

简单的理解就是2个或多个用者同时编辑相同的数据。这里的用者可能是:实际用户、不同服务、不同的代码段(使用多线程),及其在断开式和连接式情况下可能发生的情况。

并发控制理论根据建立并发控制的方法而分为两类:

悲观并发控制(Pessimistic Concurrency)

一个锁定系统,可以阻止用户以影响其他用户的方式修改数据。如果用户执行的操作导致应用了某个锁,只有这个锁的所有者释放该锁,其他用户才能执行与该锁冲突的操作。这种方法之所以称为悲观并发控制,是因为它主要用于数据争用激烈的环境中,以及发生并发冲突时用锁保护数据的成本低于回滚事务的成本的环境中。

简单的理解通常通过“独占锁”的方法。获取锁来阻塞对于别的进程正在使用的数据的访问。换句话说,读者和写者之间是会互相阻塞的 ,这可能导致数据同步冲突。

乐观并发控制(Optimistic Concurrency)

在乐观并发控制中,用户读取数据时不锁定数据。当一个用户更新数据时,系统将进行检查,查看该用户读取数据后其他用户是否又更改了该数据。如果其他用户更新了数据,将产生一个错误。一般情况下,收到错误信息的用户将回滚事务并重新开始。这种方法之所以称为乐观并发控制,是由于它主要在以下环境中使用:数据争用不大且偶尔回滚事务的成本低于读取数据时锁定数据的成本。

(以上摘自SQL Server2008 MSDN文档)

NHibernate支持乐观并发控制

NHibernate提供了一些方法来支持乐观并发控制:在映射文件中定义了<version> 节点和<timestamp>节点。其中<version> 节点用于版本控制,表明表中包含附带版本信息的数据。<timestamp>节点用于时间截跟踪,表明表中包含时间戳数据。时间戳本质上是一种对乐观锁定不是特别安全的实现。但是通常而言,版本控制方式是首选的方法。当然,有时候应用程序可能在其他方面使用时间戳。

下面用两幅图显示这两个节点映射属性:

看看它们的意义:

实例分析

下面用一个例子来实现乐观并发控制,这里使用Version版本控制。

1.修改持久化Customer类:添加Version属性public class Customer{public virtual int CustomerId { get; set; }//版本控制public virtual int Version { get; set; }public virtual string Firstname { get; set; }public virtual string Lastname { get; set; }}2.修改映射文件:添加Version映射节点"1.0" encoding="utf-8" ?><"urn:nhibernate-mapping-2.2" "DomainModel"> <"DomainModel.Entities.Customer,DomainModel" table="Customer"><""Int32" unsaved-value="0"><"native"></generator></id><""integer" unsaved-value="0"/><"""false"/><"""false"/> </class></hibernate-mapping>3.修改数据库,添加Version字段

具体参数:[Version] [int] NOT NULL 默认值为1,当然了修改数据库是最原始的方式了,如果你会使用SchemaExport,可以直接利用持久化类和映射文件生成数据库,以后在介绍如何使用这个。

4.并发更新测试

在测试之前,我们先看看数据库中什么数据,预知一下:

编写并发更新测试代码:

查询2次CustomerId为1的客户,这里就是上面的第一条数据,第一个修改为"CnBlogs",第二个修改为"",两者同时更新提交。你想想发生什么情况?

[Test]public void UpdateConcurrencyViolationCanotThrowException(){Customer c1 = _transaction.GetCustomerById(1);Customer c2 = _transaction.GetCustomerById(1);c1.Name.Firstname = "CnBlogs";c2.Name.Firstname = "";_transaction.UpdateCustomerTransaction(c1);_transaction.UpdateCustomerTransaction(c2);}

让我们去看看数据库吧,一目了然:

我们发现CustomerId为1的客户更新了FirstName数据,并且Version更新为2。你知道什么原理了吗?看看这步NHibernate生成的SQL语句(我的可能比你的不一样):先查询数据库,在直接更新数据,看看NHibernate多么实在,明显做了一些优化工作。

, , ,,, , casewhen 10 end as clazz_0_ FROM Customer customer0_ left outer join PreferredCustomer customer0_1_CustomerId ‘1’@p2 ;5.并发删除测试可是却依旧为对方擦去嘴角的油渍。

NHibernate之旅(7):初探NHibernate中的并发控制

相关文章:

你感兴趣的文章:

标签云: