WSORM:为WSBLog写的简单ORM(五)

来源:互联网 发布:查淘宝优惠券的插件 编辑:程序博客网 时间:2024/04/29 18:59

我们说说数据库的并发控制问题,WSORM通过版本控制实现了乐观锁。

它的实现原理是什么样的呢?大家可以用“ORM 乐观锁”google一下,应该可以找到相应的文章。这里举例简述一下:

某银行系统的数据库中有一张“帐户表”,里面保存了“帐户余额”记录,我们在这个表中设计了一个整形的“Version”字段。

在读取帐户余额时,我们把版本号“Version”字段一同读取出来。在更新帐户余额时,比对刚才“已经读取出来的版本号”与“数据库中的最新版本号”,如果读取出来的版本号等于数据库中的版本号,则予以更新,否则报错。

举例说,A客户在银行柜台上从某帐户中提款,银行柜台的系统客户端读取账户余额为1000元,并连带读取出记录版本号为5;恰好此时,B客户在某地自动柜员机上也从同一帐户中取款,读取账号余额1000元,版本号也为5。

A客户取款500元后,账户余额应被更新为500。A客户这边的银行柜台系统客户端“在更新帐户余额的同时检查数据库中的记录版本号”,如果版本号仍为5,则将版本号加1,把版本号变更为6,同时更新帐户余额信息为500。

我们假设A客户这边首先取款成功,看看接下来B客户这边系统客户端的处理情况:

B客户领款后也要变更数据库,B客户这边的自动柜员机系统所取得的帐户余额记录其版本号为5,但“更新帐户记录的同时检查数据库中的记录版本号”,发现其已经被更新为6,放弃更新数据库。自动柜员机系统可以提示B客户取款失败,请客户重新进行取款操作。

怎么样才能在“在更新帐户余额的同时检查数据库中的记录版本号”,这里面有一个巧妙的方法,把“Version=已读取的版本号”作为更新条件对记录进行更新,如果更新影响的行数为0,则说明读取的版本已经过期,更新失败。

我们看看WSORM是怎么做的。

首先,我们在Northwind数据库的产品信息Products表中增加一个整形字段Version,不允许为Null,默认值为0。

然后修改类Product的定义,保证已经添加了Version这个Field,并且建立了和数据库中Version字段的映射信息:

public class Product
{

 
public static ObjectMap GetObjectMap()
 
{
  ObjectMap omap 
= new ObjectMap(typeof(Product),"Products");
  omap.MemberMaps.Add(
"ID""ProductID", DbFieldTypes.Int, MemberMapTypes.Identity);
  omap.MemberMaps.Add(
"ProductName""ProductName", DbFieldTypes.String, MemberMapTypes.NormalField);
  omap.MemberMaps.Add(
"SupplierID""SupplierID", DbFieldTypes.Int, MemberMapTypes.NormalField);
  omap.MemberMaps.Add(
"CategoryID""CategoryID", DbFieldTypes.Int, MemberMapTypes.NormalField);
  omap.MemberMaps.Add(
"QuantityPerUnit""QuantityPerUnit", DbFieldTypes.String, MemberMapTypes.NormalField);
  omap.MemberMaps.Add(
"UnitPrice""UnitPrice", DbFieldTypes.Money, MemberMapTypes.NormalField);
  omap.MemberMaps.Add(
"UnitsInStock""UnitsInStock", DbFieldTypes.Int, MemberMapTypes.NormalField);
  omap.MemberMaps.Add(
"UnitsOnOrder""UnitsOnOrder", DbFieldTypes.Int, MemberMapTypes.NormalField);
  omap.MemberMaps.Add(
"ReorderLevel""ReorderLevel", DbFieldTypes.Int, MemberMapTypes.NormalField);
  omap.MemberMaps.Add(
"Discontinued""Discontinued", DbFieldTypes.Boolean, MemberMapTypes.NormalField);

  
//如果需要使用版本控制,需要在Products表中添加一个Version字段,Product添加一个Version成员,然后添加以下字段影射
  omap.MemberMaps.Add("Version""Version", DbFieldTypes.Int, MemberMapTypes.Version);

  
return omap;
 }


 
public int ID;

 
public string ProductName;

 
public int SupplierID;

 
public int CategoryID;

 
public string QuantityPerUnit;

 
public decimal UnitPrice;

 
public int UnitsInStock;

 
public int UnitsOnOrder;

 
public int ReorderLevel;

 
public bool Discontinued;
 
 
public int Version;

 
public Product()
 
{
 }

}

 

我们写一个下面这样的测试函数,并且在代码中设置一个断点(见注释):

 


private void saveAndDeleteProductInfo()
{

 ISession session 
= this.northwindFactory.CreateSession();
 Product product 
= new Product();
 product.ProductName 
= "Outback Lager test--";
 product.SupplierID 
= 7;
 product.CategoryID 
= 1;
 product.QuantityPerUnit 
= "24 - 355 ml bottles";
 product.UnitPrice 
= 15.0000M;
 product.UnitsInStock 
= 15;
 product.UnitsOnOrder 
= 10;
 product.ReorderLevel 
= 30;
 product.Discontinued 
= false;

 System.Diagnostics.Debug.WriteLine(
"==================================================");
 session.Save(product);
 session.Execute();
 
 
//注意,我们在下一句设置一个断点!
 product.ProductName = "Outback Lager test----";
 System.Diagnostics.Debug.WriteLine(
"==================================================");
 session.Save(product);
 session.Execute();
 
 session.Delete(product);
 session.Execute();
}


 

执行到断点处,Debug的输出如下:


insert into Products (ReorderLevel,Discontinued,CategoryID,ProductName,QuantityPerUnit,UnitsInStock,UnitsOnOrder,Version,UnitPrice,SupplierID) values (@ReorderLevel,@Discontinued,@CategoryID,@ProductName,@QuantityPerUnit,@UnitsInStock,@UnitsOnOrder,@Version,@UnitPrice,@SupplierID)
ReorderLevel : 30
Discontinued : False
CategoryID : 1
ProductName : Outback Lager test--
QuantityPerUnit : 24 - 355 ml bottles
UnitsInStock : 15
UnitsOnOrder : 10
Version : 0
UnitPrice : 15.0000
SupplierID : 7

我们在断点处停住,马上去检查一下数据库的Products表,发现记录确实已经成功添加到表中。

我们手工把新插入的记录的Version字段的值改为1。

继续执行代码,程序会抛出异常,Debug的输出如下:


==================================================
update Products set
ProductName=@ProductName,Version=@Version where ProductID=110 and Version=0
ProductName : Outback Lager test----
Version : 1
未处理的“com.oucsoft.WSORM.WSORMException”类型的异常出现在 WSORM.exe 中。

——我们可以看到,WSBLog是将“where ProductID=110 and Version=0”作为update的条件。一旦发现update影响的行数为0,WSBLog就会回滚数据库事务,并且向上抛出异常。

 

原创粉丝点击