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

本节内容

  • 什么是并发控制?
    • 悲观并发控制(Pessimistic Concurrency)
    • 乐观并发控制(Optimistic Concurrency)
  • NHibernate支持乐观并发控制
  • 实例分析
  • 结语

什么是并发控制?

当很多人试图同一时候改动数据库中的数据时,必须实现一个控制系统,使一个人所做的改动不会对他人所做的改动产生负面影响。

这称为并发控制。

简单的理解就是2个或多个用者同一时候编辑同样的数据。

这里的用者可能是:实际用户、不同服务、不同的代码段(使用多线程),及其在断开式和连接式情况下可能发生的情况。

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

悲观并发控制(Pessimistic Concurrency)

一个锁定系统,能够阻止用户以影响其它用户的方式改动数据。假设用户运行的操作导致应用了某个锁,仅仅有这个锁的全部者释放该锁。其它用户才干运行与该锁冲突的操作。

这样的方法之所以称为悲观并发控制,是由于它主要用于数据争用激烈的环境中。以及发生并发冲突时用锁保护数据的成本低于回滚事务的成本的环境中。

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

乐观并发控制(Optimistic Concurrency)

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

(以上摘自SQL Server2008 MSDN文档)

NHibernate支持乐观并发控制

NHibernate提供了一些方法来支持乐观并发控制:在映射文件里定义了<version> 节点和<timestamp>节点。当中<version> 节点用于版本号控制,表明表中包括附带版本号信息的数据。

<timestamp>节点用于时间截跟踪。表明表中包括时间戳数据。

时间戳本质上是一种对乐观锁定不是特别安全的实现。可是通常而言,版本号控制方式是首选的方法。当然。有时候应用程序可能在其它方面使用时间戳。

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

节点属性

看看它们的意义:

  • access(默觉得property):NHibernate用于訪问特性值的策略。
  • column(默觉得特性名):指定持有版本号号的字段名或者持有时间戳的字段名。

  • generated:生成属性,可选never和always两个属性。
  • name:持久化类的特性名或者指定类型为.NET类型DateTime的特性名。
  • type(默觉得Int32):版本号号的类型,可选类型为Int64、Int32、Int16、Ticks、Timestamp、TimeSpan。注意:<timestamp>和<version type="timestamp">是等价的。
  • unsaved-value(在版本号控制中默认是“敏感”值,在时间截默认是null):表示某个实例刚刚被实例化(尚未保存)时的版本号特性值,依靠这个值就能够把这样的情况和已经在先前的会话中保存或装载的游离实例区分开来。(undefined指明使用标识特性值进行推断)

实例分析

以下用一个样例来实现乐观并发控制,这里使用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映射节点

<?xml version="1.0" encoding="utf-8" ?

> <

hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="DomainModel" namespace="DomainModel"> <class name ="DomainModel.Entities.Customer,DomainModel" table="Customer"> <id name="CustomerId" column="CustomerId" type="Int32" unsaved-value="0"> <generator class ="native"></generator> </id> <version name="Version" column="Version" type="integer" unsaved-value="0"/> <property name="Firstname" column ="Firstname" type="string" length="50" not-null="false"/> <property name ="Lastname" column="Lastname" type="string" length="50" not-null="false"/> </class> </hibernate-mapping>

3.改动数据库,加入Version字段

详细參数:[Version] [int] NOT NULL 默认值为1,当然了改动数据库是最原始的方式了,假设你会使用SchemaExport,能够直接利用持久化类和映射文件生成数据库。以后在介绍怎样使用这个。

4.并发更新測试

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

原始数据

编写并发更新測试代码:

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

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

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

并发更新之后数据

我们发现CustomerId为1的客户更新了FirstName数据,而且Version更新为2。

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

SELECT customer0_.CustomerId as CustomerId3_0_, 
customer0_.Version as Version3_0_, 
customer0_.Firstname as Firstname3_0_,
customer0_.Lastname as Lastname3_0_,
customer0_1_.OrderDiscountRate as OrderDis2_4_0_, 
customer0_1_.CustomerSince as Customer3_4_0_, 
case when customer0_1_.CustomerId is not null then 1 when customer0_.CustomerId is not null then 0 
end 
as clazz_0_ FROM Customer 
customer0_ left outer join PreferredCustomer customer0_1_
on customer0_.CustomerId=customer0_1_.CustomerId 
WHERE customer0_.CustomerId=@p0; @p0 = '1'UPDATE Customer SET Version = @p0, Firstname = @p1, Lastname = @p2 
WHERE CustomerId = @p3 AND Version = @p4;
@p0 = '2', @p1 = 'www.cnblogs.com', @p2 = 'Lee', @p3 = '1', @p4 = '1'

5.并发删除測试

我们再来编写一个測试用于并发删除。

查询2次CustomerId为2的客户。这里就是上面的第二条数据,两者同一时候删除数据。

你想想发生什么情况?

[Test]
[ExpectedException(typeof(NHibernate.StaleObjectStateException))]
public void DeleteConcurrencyViolationCanotThrowException()
{Customer c1 = _transaction.GetCustomerById(2);Customer c2 = _transaction.GetCustomerById(2);_transaction.DeleteCustomerTransaction(c1);_transaction.DeleteCustomerTransaction(c2);
}

同理,看看数据库里的数据,第二条数据不见了。

并发删除之后数据

其生成SQL的查询语句同上面一样,仅仅是一条删除语句:

DELETE FROM Customer WHERE CustomerId = @p0 AND Version = @p1; @p0 = '2', @p1 = '1'

好了,这里通过两个简单的实例说明了在NHibernate中对并发控制的支持。

相信有了一定的了解,大家也能够编写一些有趣的測试来试试NHibernate中的乐观并发控制。

结语

这一篇我们初步探索了NHibernate中的并发控制,并用一个典型的实例分析了详细怎么做。我想这仅仅是蜻蜓点水,很多其它的乐趣就自己探索吧。比方在不同的Session中的并发啊,更新啊,删除啊......

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/290421.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

期望DP

期望DP的一般做法是从末状态開始递推&#xff1a; Problem DescriptionAkemi Homura is a Mahou Shoujo (Puella Magi/Magical Girl).Homura wants to help her friend Madoka save the world. But because of the plot of the Boss Incubator, she is trapped in a labyrinth …

神奇的[Caller*]属性

前言上次&#xff0c;我们《使用 CallerArgumentExpression 检查弃元参数》&#xff0c;它实际是利用编译器编译时将变量名称传入。其实&#xff0c;.NET中提供了多个[Caller*]属性&#xff0c;帮助我们轻松获取调用者信息。CallerFilePathAttribute允许获取包含调用方的源文件…

java dateTime + long

2019独角兽企业重金招聘Python工程师标准>>> public static void main(String[] args) throws Exception{SimpleDateFormat sdfnew SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // long timeStartsdf.parse("2011-09-20 12:30:45").getTime();l…

.NET Core中异常过滤器ExceptionFilter的使用介绍

介绍实现需要继承IExceptionFilter 或 IAsyncExceptionFilter。可用于实现常见的错误处理策略。使用场景首先讲一下我们为什么要使用异常过滤器 &#xff0c;如果业务场景复杂&#xff0c;只使用HttpStatusCode&#xff0c;抛出异常后,后期要加很多字段来描述。那么这种就比较不…

程序一启动检查网络,如果没有网络就退出程序

转载于:https://www.cnblogs.com/songxing10000/p/4823812.html

看小说的这些年

从大一开始&#xff0c;就开始看起了小说&#xff0c;不是那种名著类型&#xff0c;而是快餐小说&#xff0c;玄幻、都市、言情、科幻&#xff0c;什么都会看&#xff0c;因为看多了&#xff0c;就会发现&#xff0c;已经没什么可以看的。 谈起快餐小说&#xff0c;已经有很多被…

COMA(一): Learning to Communicate with Deep Multi-Agent Reinforcement Learning 论文讲解

Learning to Communicate with Deep Multi-Agent Reinforcement Learning 论文讲解 论文链接&#xff1a;https://papers.nips.cc/paper/6042-learning-to-communicate-with-deep-multi-agent-reinforcement-learning.pdf &#xff08;这篇论文是COMA三部曲中的第&#xff08…

C和指针之指针数组和指向数组的指针

1、指针数组 定义一个指针数组&#xff0c;该数组中每个元素是一个指针&#xff0c;每个指针指向哪里就需要程序中后续再定义int *p[10]; 2、指向数组的指针 定义一个数组指针&#xff0c;该指针指向含10个元素的一维数组&#xff08;数组中每个元素是int型&#xff09;int (*p…

SSH 远程执行任务

SSH 是 Linux 下进行远程连接的基本工具&#xff0c;但是如果仅仅用它来登录那可是太浪费啦&#xff01;SSH 命令可是完成远程操作的神器啊&#xff0c;借助它我们可以把很多的远程操作自动化掉&#xff01;下面就对 SSH 的远程操作功能进行一个小小的总结。远程执行命令如果我…

分库分表之历史表如何选择最佳分片路由规则

前言先别急着关闭,我相信这篇文章应该是所有讲分表分库下的人都没有和你们讲过的一种分片模式,外面的文章基本上都是教你如何从零开始分片,现在我将讲解的是如何从1开始分片项目地址github地址 https://github.com/dotnetcore/sharding-coregitee地址 https://gitee.com/dotnet…

COMA(二):Counterfactual Multi-Agent Policy Gradients 论文讲解

Counterfactual Multi-Agent Policy Gradients 论文链接&#xff1a;https://arxiv.org/pdf/1705.08926.pdf 1. 问题提出&#xff08;解决了什么问题&#xff1f;&#xff09; 在现实世界中&#xff0c;有非常多的问题需要多个单位之间的“合作”才能完成任务&#xff0c;这就…

lecture6-mini批量梯度训练及三个加速的方法

Hinton的第6课&#xff0c;这一课中最后的那个rmsprop&#xff0c;关于它的资料&#xff0c;相对较少&#xff0c;差不多除了Hinton提出&#xff0c;没论文的样子&#xff0c;各位大大可以在这上面研究研究啊。 一、mini-批量梯度下降概述 这部分将介绍使用随机梯度下降学习来训…

Dapr集成之GRPC 接口

Dapr 为本地调用实现 HTTP 和 gRPC API 。通常大家第一时间想到的是通过 gRPC 调用 Dapr&#xff0c;更重要的一点是Dapr 也可以通过 gRPC 与应用程序通信。要做到这一点&#xff0c;原理很简单&#xff0c;应用程序需要托管一个gRPC服务器&#xff0c;并实现 Dapr 的GRPC 规范…

jQuery Validate验证框架详解

jQuery Validate验证框架详解 jQuery校验官网地址&#xff1a;http://bassistance.de/jquery-plugins/jquery-plugin-validation 一、导入js库 <script type"text/javascript" src"<%path %>/validate/jquery-1.6.2.min.js"></script> &…

RNN入门笔记

本笔记来源自Youtube李宏毅老师的RNN视频归纳&#xff0c;主要分为以下几个知识点: RNN 的特点RNN 的几种实现方法 (Simple RNN, LSTM)RNN 的训练不稳定性RNN 的keras实现 (定长和变长输入案例) Recurrent Neural Network Feature of RNN Differ from normal Neural Networ…

WPF 基础控件之 DatePicker 样式

此群已满340500857 &#xff0c;请加新群458041663由于微信群人数太多入群请添加小编微信号yanjinhuawechat 或 W_Feng_aiQ 邀请入群需备注WPF开发者 PS&#xff1a;有更好的方式欢迎推荐。支持NugetInstall-Package WPFDevelopers.Minimal -Version 3.2.001—代码如下一、创建…

stagefright框架(四)-Video Buffer传输流程

這篇文章將介紹Stagefright中是如何和OMX video decoder传送buffer。 (1) OMXCodec會在一開始的時候透過read函式來傳送未解碼的data給decoder&#xff0c;並且要求decoder將解碼後的data傳回來 status_t OMXCodec::read(...){ if (mInitialBufferSubmit) { mInitialBuffe…

微信支付四大支付模式分别有哪些区别?

微信支付是集成在微信客户端的支付功能&#xff0c;用户可以通过手机完成快速的支付流程。微信支付已为百货、餐厅、便利店、酒店、快递、景区、医院、售货机等提供了支付与营销的全方位支持。 目前微信支付已实现刷卡支付、扫码支付、公众号支付、APP支付&#xff0c;并提供企…

利用Deep Reinforcement Learning训练王者荣耀超强AI

Mastering Complex Control in MOBA Games with Deep Reinforcement Learning&#xff08;一&#xff09;知识背景&#xff08;二&#xff09;系统架构&#xff08;三&#xff09;算法结构3.1 Target Attention3.2 利用LSTM学习技能连招释放3.3 Decoupling of Control Dependen…

C和指针之编译出现warning: implicit declaration of function ‘matrix_multiply‘ is invalid in C99问题

1、问题 在我的mac上编译一个c文件&#xff0c;出现下面错误2、原因和解决办法 是因为我用vim的时候&#xff0c;把函数名少写了一个字符导致&#xff0c;把这个函数名改正就行了。