首页 > 编程知识 正文

死锁的四个必要条件,mysql悲观锁和乐观锁定义

时间:2023-05-04 00:34:21 阅读:34482 作者:4784

这方面的资料网上很多,以下都转载

1、悲观锁定,顾名思义,是指在数据处理的整个过程中使数据处于锁定状态,因为它对包括系统当前其他事务和来自外部系统的事务在内的外部数据的修改持保守态度。 悲观锁定的实现往往依赖于数据库提供的锁定机制(只有数据库层提供的锁定机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了锁定机制,外部系统也是如此)

数据保持不变)。

2、乐观锁定(最佳锁定) )。

对于悲观锁定,乐观锁定机制采用了更宽松的锁定机制。 悲观的锁定通常通过数据库锁定机制来实现,以最大限度地确保操作的独占性。 但是,这将导致数据库性能方面的巨大开销。 特别是在长事务中,这种开销往往是无法承受的。

乐观锁定机制在一定程度上解决了这个问题。 乐观锁定通常基于数据版本(Version )的记录机制来实现。 什么是数据版本? 也就是说,向数据中添加版本id。 通常,通过在数据库表中添加" version "字段来提供基于数据库表的版本控制解决方案。 读取数据时,一起读取此版本号,然后更新时,在此版本号上加1。 此时,将提交数据的版本数据与数据库表中相应记录的当前版本信息进行匹配,如果提交数据的版本号大于数据库表的当前版本号则更新,否则视为过期数据

基本上,数据库的乐观锁定和悲观锁定方法主要是解决以下假设情况,避免更新问题:

一个比较清楚的场景

以下假设的实际场景有助于理解这个问题。

假设网络上的用户订购了一本书并买了它。 那时,数据库中有一个订单编号为001的订单,其中有一个名为“已启用”的status字段,表示该订单有效。 后台管理员检查此001订单,发现状态有效的用户在订单时出错,因此取消订单。 此SQL :更新顺序设置状态=“取消”where顺序_ id=001; 由于后勤管理员在b阶段看到状态有效,因此用户在c阶段取消了订单,但管理员没有更新界面,看到的订单状态有效。 然后点击“发货”按钮,将该订单发送到物流部门,同时执行以下SQL。 将订单状态更改为已发货: update order _ table set status=‘已发货’where order _ id=001,但实际上我们分别详细分析了乐观锁定的做法和悲观锁定的做法。

这里引用维客的定义做更权威的引用说明

3358 en.Wikipedia.org/wiki/lock _ (数据库)

therearemechanismsemployedtomanagetheactionsofmultipleconcurrentusersonadatabasehttp://www.Sina.com/. thetwotypesoflockkkypes

3358 www.Sina.com/:3358 www.Sina.com/d,with the intention of updating it, http://www.Sina.com/t.thismeansnooneelsecanmanipulatethatrecorduntiltheuserreleasesthelock.thedownsideisthatuserscanberescanbecanbelock therebyslowingtheoverallsystemresponseandcausingfrustration.http://www.Sina.com/3360 thisismainlyusedinenvironmentswherentswheredswheredetswheswherered werethecostofprotectingdatathroughlocksislessthanthecostofrollingbacktransactionsifconcurrencyconflictsocccur.pesssimimisticonconconcon dwhenlocktimeswillbeshort,asinprogrammaticprocessingofrecords。

Pessimistic concurrency requires a persistent connection to the database and is not a scalable option when users are interacting with data, because records might be locked for relatively large periods of time. It is not appropriate for use in web application development.

本质上,这里wiki的意思就是,悲观锁和乐观锁都是为了解决丢失更新问题或者是脏读。悲观锁和乐观锁的重点就是是否在读取记录的时候直接上锁。悲观锁的缺点很明显,需要一个持续的数据库连接,这在web应用中已经不适合了。

观点1:只有冲突非常严重的系统才需要悲观锁;

分析:这是更准确的说法;我在原文中说到:

“所有悲观锁的做法都适合于状态被修改的概率比较高的情况,具体是否合适则需要根据实际情况判断。”,表达的也是这个意思,不过说法不够准确;的确,之所以用悲观锁就是因为两个用户更新同一条数据的概率高,也就是冲突比较严重的情况下,所以才用悲观锁。

观点2:最后提交前作一次select for update检查,然后再提交update也是一种乐观锁的做法

分析:这是更准确的说法;

的确,这符合传统乐观锁的做法,就是到最后再去检查。但是wiki在解释悲观锁的做法的时候,’It is not appropriate for use in web application development.’, 现在已经很少有悲观锁的做法了,所以我自己将这种二次检查的做法也归为悲观锁的变种,因为这在所有乐观锁里面,做法和悲观锁是最接近的,都是先select for update,然后update

*****除了上面的观点1和观点2是更准确的说法,下面的所有观点都是错误的***********

观点3:这个问题的原因是因为数据库隔离级别是uncommitted read级别;

分析:这个观点是错误的;

这个过程本身就是在read committed隔离级别下发生的,从a到d每一步,尤其是d这步,并不是因为读到了未提交的数据,仅仅是因为用户界面没有刷新[事实上也不可能做自动刷新,这样相当于数据库一发生改变立刻要刷新了,这需要监听数据库了,显然这是简单问题复杂化了];

观点4:悲观锁是指一个用户在更新数据的时候,其他用户不能读取这条记录;也就是update阻塞读才叫悲观锁;

分析:这个观点是错的;

这在db2背景的开发中尤其常见;因为db2默认就是update会阻塞读;但是这是各个数据库对读写的时候上锁的并发处理实现不一样。但这根本不是悲观锁乐观锁的区别。Oracle可以做到写不阻塞读仅仅是因为做了多版本并发控制(Multiversion concurrency control), http://en.wikipedia.org/wiki/Multiversion_concurrency_control;

但是在Oracle里面,一样可以做乐观锁和悲观锁的控制。这本质上是应用层面的选择。

观点5:Oracle实际上用的就是乐观锁

分析:这个观点是错的;

前面说了,Oracle的确可以做到写不阻塞读,但是这不是悲观锁和乐观锁的问题。这是因为实现了多版本并发控制。按照wiki的定义,悲观锁和乐观锁是在应用层面选择的。Oracle的应用只要在第二步做了select for update,就是悲观锁的做法;

况且Oracle在任何隔离级别下,除了分布式事务两阶段提交的短暂时间,其他所有情况下都不存在写阻塞读的情况,如果按照这个观点的话那Oracle已经不能做悲观锁了-_-

观点6:不需要这么麻烦,只需要在d这步,最后提交更新的时候再做一个普通的select检查一下就可以;[就是double check的做法]

分析:这个观点是错的。

这个做法其实在http://www.hetaoblog.com/database-lost-update-pessimistic-lock/,’3. 传统悲观锁做法的变通’这节已经说明了,如果要这么做的话,仍然需要在最后提交更新前double check的时候做一个select for update, 否则select结束到update提交前的时间仍然有可能记录被修改;

观点7:应该尽可能使用悲观锁;

分析:这个观点是错的;

a. 根据悲观锁的概念,用户在读的时候(b这步)就会将记录锁住,直到更新结束的时候才会将锁释放,所以整个锁的过程时间比较长;

b. 另外,悲观锁需要有一个持续的数据库连接,这在当今的web应用中已经几乎不存在;wiki上也说了, 悲观锁‘is not appropriate for use in web application development.’

所以,现在大部分应用都应该是乐观锁的;

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。