出处:http://www.cnblogs.com/chenlulouis/ 

今天,在这里,我们将讨论的是在实际生产过程中,对于并发控制你是选择乐观锁还是悲观锁。这两种锁各自的应用环境应该怎样选择?

实际生产环境里边,如果并发量不大,完全可以使用悲观锁定的方法,这种方法使用起来非常方便和简单。但是如果系统的并发非常大的话,悲观锁定会带来非常大的性能问题,所以就要选择乐观锁定的方法。

悲观锁假定其他用户企图访问或者改变你正在访问、更改的对象的概率是很高的,因此在悲观锁的环境中,在你开始改变此对象之前就将该对象锁住,并且直到你提交了所作的更改之后才释放锁。悲观的缺陷是不论是页锁还是行锁,加锁的时间可能会很长,这样可能会长时间的限制其他用户的访问,也就是说悲观锁的并发访问性不好。

乐观锁则认为其他用户企图改变你正在更改的对象的概率是很小的,因此乐观锁直到你准备提交所作的更改时才将对象锁住,当你读取以及改变该对象时并不加锁。可见乐观锁加锁的时间要比悲观锁短,乐观锁可以用较大的锁粒度获得较好的并发访问性能。

但是如果第二个用户恰好在第一个用户提交更改之前读取了该对象,那么当他完成了自己的更改进行提交时,数据库就会发现该对象已经变化了,这样,第二个用户不得不重新读取该对象并作出更改。这说明在乐观锁环境中,会增加并发用户读取对象的次数。以版本控制系统为例,来说说两种最基本的并发性问题。

丢失更新:

小张想修改源代码里面的a方法,正在她修改的同时,小李打开了这个文件,修改了b方法并且保存了文件,等小张修改完成后,保存文件,小李所做的修改就被覆盖了。

不一致的读:

小张想要知道包里面一共有多少个类,包分了a,b两个子包。小张打开a包,看到了7个类。突然小张接到老婆打来的电话,在小张接电话的时候,小李往a包中加了2个类,b包中加了3个类(原先b包中是5个类)。

小张接完电话后再打开b包,看到了8个类,很自然得出结论:包中一共有15个类。

很遗憾,15个永远不是正确的答案。在小李修改前,正确答案是12(7+5),修改后是17(9+8)。这两个答案都是正确的,虽然有一个不是当前的。但15不对,因为小张读取的数据是不一致的。

小结:不一致读指你要读取两种数据,这两种数据都是正确的,但是在同一时刻两者并非都正确。

隔离和不可变:

在企业应用中,解决并发冲突的两种常用手段是隔离和不可变。

只有当多个活动(进程或者线程)同时访问同一数据时才会引发并发问题。一种很自然的思路就是同一时刻只允许一个活动访问数据。如果小张打开了文件,就不允许其他人打开,或者其他人只能通过只读的方式打开副本,就可以解决这个问题。

隔离能够有效减少发生错误的可能。我们经常见到程序员陷入到并发问题的泥潭里,每一段代码写完都要考虑并发问题,这样太累了。我们可以利用隔离技术创建出隔离区域,当程序进入隔离区域时不用关心并发问题。好的并发性设计就是创造这样的一些隔离区域,并保证代码尽可能的运行在其中。

另一种思路:只有当你需要修改共享的数据时才可能引发并发性问题,所以我们可以将要共享的数据制作为“不可变”的,以避免并发性问题。当然我们不可能将所有的数据都做成不可变的,但如果一些数据是不可变的,对它们进行并发操作时我们就可以放松自己的神经了。

乐观并发控制、悲观并发控制:

如果数据是可变的,并且无法隔离呢?这种情况下最常用的两种控制就是乐观并发控制和悲观并发控制。

假设小张和小李想要同时修改同一个文件。如果使用乐观锁,俩人都能打开文件进行修改,如果小张先提交了内容,没有问题,他所做的改变会保存到服务器上。但小李提交时就会遇到麻烦,版本控制服务器会检测出两种修改的冲突,小李的提交会被具体,并由小李决定该如何处理这种情况(对于绝大部分版本控制软件来说,会读取并标识出小张做的改变,然后由小李决定是否合并)。

如果使用的是悲观锁,小张先检出(check out)文件,那么小李就无法再次检出同一文件,直到小张提交了他的改变。

建议你将乐观锁想成一种检测冲突的手段,而悲观锁是一种避免冲突的手段(严格来说,乐观锁其实不能称之为“锁”,但是这个名字已经流传开了,那就继续使用吧)。一些老的版本控制系统,比如VSS 6.0使用的是悲观锁的机制。而现代的版本控制系统一般两种都支持,默认使用乐观锁。

两种锁各有优缺点。这段懒的翻译了,很明显看出,乐观锁可以提高并发访问的效率,但是如果出现了冲突只能向上抛出,然后重来一遍;悲观锁可以避免冲突的发生,但是会降低效率。

选择使用那一种锁取决于访问频率和一旦产生冲突的严重性。如果系统被并发访问的概率很低,或者冲突发生后的后果不太严重(所谓后果应该指被检测到冲突的提交会失败,必须重来一次),可以使用乐观锁,否则使用悲观锁。

我们可以使用两种形式的并发控制策略:乐观并发控制和悲观并发控制。

假设martin和David同时都要编辑Customer文件。如果使用乐观锁策略,他们两个人都能得到一份文件的Copy,并且可以自由编辑文件。假设David第一个完成了工作,那么他可以毫无困难地更新他的修改。但是,当Martin想要提交他的修改时,并发控制策略就会开始起作用。

源代码控制系统会检测到在Martin的修改与David的修改之间存在着冲突,因而拒绝Martin的提交,并由Martin负责指出怎样处理这种情况。如果使用悲观锁策略,只要有人先取出文件,其他人就不能对该文件进行编辑。因此,假如是Martin先取了文件,那么David就只能在Martin完成任务并提交之后才能对该文件进行操作。

如果把乐观锁看作是关于冲突检测的,那么悲观锁就是关于冲突避免的。在实际应用的源代码控制系统中,这两种策略都可以被使用,但是现在大多数源代码开发者更倾向于使用乐观锁策略。

有一种很有道理的说法:乐观锁并不是真正的锁定,但是这种叫法很方便并且广泛流传,以至于不容忽略。

这两种策略各有优缺点。悲观锁的问题是减少了并发的程序。当Martin正对一个被他加锁的文件进行编辑的时候,其它人只能等着。使用过悲观的源代码控制人都知道这是一种多么令人丧气的事情。对于企业数据,情况经常会变得更加糟糕,只要有人在编辑,其他人就无法进行读取,更加说进行编辑了。

乐观锁策略则允许人们更自由一些,因为只有在提交的时候才有可能遇到阻碍。该策略的问题在于当冲突的时候会发生什么样的事情呢?事实上,David之后的所有人在提交的时候都必须读取David修改过的那个版本,并指出怎样合并自己和David的修改,然后再提交一个重新修改过的最新版本。

有了源代码控制系统,这样做并不会有什么麻烦。在许多场合下,源代码控制系统确实能够自动进行合并操作,甚至在无法自动合并的时候,也能让使用都很容易看出不同文件版本之间的差别。但是,业务数据通常都是很难被自动合并的,所以经常只能扔掉原来的东西,然后从头开始。

在乐观锁和悲观锁之间进行选择的标准是:冲突的频率与严重性。如果冲突很少,或者冲突的后果不会很严重,那么通常情况下应该选择乐观锁,因为它能得到更好的并发性,而且更容易实现。但是,如果冲突的结果对于用户来说痛苦的,那么就需要使用悲观策略。

乐观锁的局限是:

只能在提交数据时才发现业务事务将要失败,而且在某些情况下,发现失败太迟的代价会很大。用户可能花了一个小时的时间输入一份租约的详细信息,错误太多会让用户对系统失去信心。另一个方法是使用悲观锁,它可以尽早地发现错误,但理难以编程实现,而且会降低系统的灵活性。

注:以上是对并发控制中的乐观锁策略和悲观锁策略概念及解决思路的文字描述,下面我将对项目中具体怎么实现乐观锁策略及悲观锁策略进行描述。

乐观锁策略实现方法:

就是用C#中或SQL中的事务来实现数据操作不成功就回滚,个人感觉火车站卖票系统也是这样操作的,我们看到显示屏上有少量剩余票,但我们去买又打不出来。

悲观锁策略实现方法:

1、普通的aspx页面,当用户点提交后,直接将提交及相关按钮的enabel改为false,直到提交事件完成后,再改回来。另外在数据层那一块,每次提交数据更改时,都需要判断数据以前的状态是否改变,以防止有并发改变的情况出现。

2、jquery中,在jquery中,可以设置一个全局变量,提交时,先判断全局变量状态,如不允许提交则直接返回,如允许提交时,则先将全局变量置为“不允许提交”,后开始提交,提交完成后,在jquery的post方法的callback方法中,再将全局变量改为“允许提交”。

3、弹出式窗口修改页面,则用模态方式弹出,如web页面中,可用window.show ModalDialog()来实现模态方式打开修改页面,来确保始终只有一个修改页面被打开。这是从数据操作页面处就悲观锁定了数据,而不是在数据库里面悲观锁定。

数据库并发控制,选择乐观锁还是悲观锁?相关推荐

  1. 数据库中的乐观锁与悲观锁详解

    目录 悲观锁 乐观锁 悲观锁实现方式 乐观锁实现方式 如何选择 悲观锁 当我们要对一个数据库中的一条数据进行修改的时候,为了避免同时被其他人修改,最好的办法就是直接对该数据进行加锁以防止并发. 这种借 ...

  2. Java开发技巧——并发控制中的乐观锁与悲观锁

    1.为什么需要锁? 在多用户环境中,在同一时间可能会有多个用户新相同的记录,这会产生冲突.这就是的并发性问题. 2.典型的冲突类型: (1)丢失新:一个事务的新覆盖了其它事务的新结果,就是所谓的新丢失 ...

  3. 并发控制中的乐观锁与悲观锁

    为什么需要锁(并发控制)? 在多用户环境中,在同一时间可能会有多个用户更新相同的记录,这会产生冲突.这就是著名的并发性问题. 典型的冲突有: (1)丢失更新:一个事务的更新覆盖了其它事务的更新结果,就 ...

  4. 数据库中的乐观锁与悲观锁

    悲观锁 当我们要对一个数据库中的一条数据进行修改的时候,为了避免同时被其他人修改,最好的办法就是直接对该数据进行加锁以防止并发. 这种借助数据库锁机制在修改数据之前先锁定,再修改的方式被称之为悲观并发 ...

  5. 数据库的乐观锁和悲观锁

    目录 悲观锁 乐观锁 对比与选择 在并发的环境下,需要用乐观锁和悲观锁来控制数据的准确性. 最终库存数量为4,但其实要是3才对,这就是并发环境下,没有做好并发控制的情况. 悲观锁 为了避免数据被同时修 ...

  6. mysql乐观锁与事务_[数据库事务与锁]详解七: 深入理解乐观锁与悲观锁

    注明: 本文转载自http://www.hollischuang.com/archives/934 在数据库的锁机制中介绍过,数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库 ...

  7. 数据库工作笔记017---还记得Oracle悲观锁和乐观锁嘛?以及hibernate对乐观悲观锁的封装

    技术交流QQ群[JAVA,.NET,BigData,AI]:170933152 今天又用到这个了,之前做分布式,很多表在设计的时候都不加各种限制以及关联了,因为加了以后,数据库以后维护,成本很大 但是 ...

  8. 浅谈实现数据库乐观锁和悲观锁

    目录 数据库乐观锁 适用场景 定义 实现方式 优点与缺点分析 优点 缺点 案例 数据库悲观锁 适用场景 定义 实现方式 悲观锁优缺点分析 优点 缺点 在单实例JVM中,常见的处理并发问题的方法有很多, ...

  9. 数据库-乐观锁和悲观锁

    写在前面: 锁根据其使用的方式可以划分为:乐观锁和悲观锁.乐观锁即乐观并发控制,悲观锁即悲观并发控制,他们是处理并发控制时主要采用的技术手段.其中,悲观锁正是数据库本身提供的锁机制实现的. 悲观锁: ...

最新文章

  1. (转)Sublime Text2 快捷键汇总
  2. python3 hmac算法简介
  3. linux怎么改程序图标,如何在Ubuntu Unity上更换应用程序图标
  4. CSharp之界面美化
  5. qpython3怎样安notebook_Windows下基于Python3安装Ipython Notebook(即Jupyter)。python –m pip install XXX...
  6. 怎么知道wx.config执行成功没_作为一个减肥40斤,且10年没反弹的普通人,这份瘦身经验分享给你...
  7. swoole 捕捉php错误,swoole怎么处理错误
  8. leetcode —— 31. 下一个排列
  9. 数据同步框架MS Sync Framework-不同场景使用例子和简要分析
  10. STM32F103C8T6单片机IAP升级
  11. CUDA 8.0 + VS2013 + win10 x64开发环境搭建
  12. JS等比例缩小图片尺寸
  13. Centos7 Kubernetes(k8s) 开发服务器(单服务器)部署 kibana
  14. Kinect v2 使用ork功能包进行物体识别
  15. 两种.luac的反编译过程
  16. MySQL 导入数据 时间数据 不准确 解决办法
  17. icp-ms质量分析器与磁质谱仪
  18. 彤云缥缈回金格,明月婵娟挂玉钩
  19. Unity3d 给人物模型添加动画
  20. load_weights` requires h5py when loading weights from HDF5

热门文章

  1. Python代码发送post请求接口测试--转载
  2. JS 简单实现公告消息自动逐条切换
  3. [译]以PostgreSQL为例,谈join计算的代价
  4. 3.5 mysql备份与恢复
  5. 部署DNS之辅助区域
  6. 【机器学习】改善LBP特征提高SVM的可分性的经验总结(一)
  7. 多目标优化算法(二)MOEAD及MOEAD与NSGA-Ⅱ的对比
  8. FFmpeg音频编码 ---- pcm转aac(使用新版ffmpeg API,亲测可用)
  9. HTML CSS JS之间的关系
  10. Hyperledger Fabric 超级账本 Java 开发区块链环境构建