`

乐观锁与悲观锁

阅读更多

悲观锁

在关系数据库管理系统里,悲观并发控制(又名“悲观锁”,Pessimistic Concurrency Control,缩写“PCC”)是一种并发控制的方法。它可以阻止一个事务以影响其他用户的方式来修改数据。如果一个事务执行的操作都某行数据应用了锁,那只有当这个事务把锁释放,其他事务才能够执行与该锁冲突的操作。
悲观并发控制主要用于数据争用激烈的环境,以及发生并发冲突时使用锁保护数据的成本要低于回滚事务的成本的环境中。

悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度(悲观),因此,在整个数据处理过程中,将数据处于锁定状态。 悲观锁的实现,往往依靠数据库提供的锁机制 (也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)

在数据库中,悲观锁的流程如下:

在对任意记录进行修改前,先尝试为该记录加上排他锁(exclusive locking)。

如果加锁失败,说明该记录正在被修改,那么当前查询可能要等待或者抛出异常。 具体响应方式由开发者根据实际需要决定。

如果成功加锁,那么就可以对记录做修改,事务完成后就会解锁了。

其间如果有其他对该记录做修改或加排他锁的操作,都会等待我们解锁或直接抛出异常。

MySQL InnoDB中使用悲观锁

要使用悲观锁,我们必须关闭mysql数据库的自动提交属性,因为MySQL默认使用autocommit模式,也就是说,当你执行一个更新操作后,MySQL会立刻将结果进行提交。set autocommit=0;

1
2
3
4
5
6
7
8
9
10
//0.开始事务
begin;/begin work;/start transaction; (三者选一就可以)
//1.查询出商品信息
select status from t_goods where id=1 for update;
//2.根据商品信息生成订单
insert into t_orders (id,goods_id) values (null,1);
//3.修改商品status为2
update t_goods set status=2;
//4.提交事务
commit;/commit work;

上面的查询语句中,我们使用了select…for update的方式,这样就通过开启排他锁的方式实现了悲观锁。此时在t_goods表中,id为1的 那条数据就被我们锁定了,其它的事务必须等本次事务提交之后才能执行。这样我们可以保证当前的数据不会被其它事务修改。

上面我们提到,使用select…for update会把数据给锁住,不过我们需要注意一些锁的级别,MySQL InnoDB默认行级锁。行级锁都是基于索引的,如果一条SQL语句用不到索引是不会使用行级锁的,会使用表级锁把整张表锁住,这点需要注意。

优点与不足

悲观并发控制实际上是“先取锁再访问”的保守策略,为数据处理的安全提供了保证。但是在效率方面,处理加锁的机制会让数据库产生额外的开销,还有增加产生死锁的机会;另外,在只读型事务处理中由于不会产生冲突,也没必要使用锁,这样做只能增加系统负载;还有会降低了并行性,一个事务如果锁定了某行数据,其他事务就必须等待该事务处理完才可以处理那行数

乐观锁

在关系数据库管理系统里,乐观并发控制(又名“乐观锁”,Optimistic Concurrency Control,缩写“OCC”)是一种并发控制的方法。它假设多用户并发的事务在处理时不会彼此互相影响,各事务能够在不产生锁的情况下处理各自影响的那部分数据。在提交数据更新之前,每个事务会先检查在该事务读取数据后,有没有其他事务又修改了该数据。如果其他事务有更新的话,正在提交的事务会进行回滚。乐观事务控制最早是由孔祥重(H.T.Kung)教授提出。

乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。

相对于悲观锁,在对数据库进行处理的时候,乐观锁并不会使用数据库提供的锁机制。一般的实现乐观锁的方式就是记录数据版本。

数据版本,为数据增加的一个版本标识。当读取数据时,将版本标识的值一同读出,数据每更新一次,同时对版本标识进行更新。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的版本标识进行比对,如果数据库表当前版本号与第一次取出来的版本标识值相等,则予以更新,否则认为是过期数据。

实现数据版本有两种方式,第一种是使用版本号,第二种是使用时间戳。

使用版本号实现乐观锁

使用版本号时,可以在数据初始化时指定一个版本号,每次对数据的更新操作都对版本号执行+1操作。并判断当前版本号是不是该数据的最新的版本号。

1
2
3
4
5
6
7
1.查询出商品信息
select (status,status,version) from t_goods where id=#{id}
2.根据商品信息生成订单
3.修改商品status为2
update t_goods
set status=2,version=version+1
where id=#{id} and version=#{version};

优点与不足

乐观并发控制相信事务之间的数据竞争(data race)的概率是比较小的,因此尽可能直接做下去,直到提交的时候才去锁定,所以不会产生任何锁和死锁。但如果直接简单这么做,还是有可能会遇到不可预期的结果,例如两个事务都读取了数据库的某一行,经过修改以后写回数据库,这时就遇到了问题。

分享到:
评论

相关推荐

    面试必备之乐观锁与悲观锁.pdf

    #### 一、悲观锁与乐观锁的概念 悲观锁和乐观锁是计算机科学中用于处理并发控制的两种不同策略,它们主要应用于多线程环境下数据的一致性和完整性保护。两种锁的设计哲学反映了对数据并发访问时的不同预期。 **...

    Hibernate的乐观锁与悲观锁

    ### Hibernate的乐观锁与悲观锁 #### 一、引言 在并发环境下,尤其是在金融、电商等业务场景中,确保数据的一致性和完整性至关重要。**Hibernate**作为一种流行的Java持久层框架,提供了多种机制来处理并发控制...

    面试必备之乐观锁与悲观锁

    【描述】:“面试必备之乐观锁与悲观锁.pdf”涉及的是并发控制中的两种重要锁机制——悲观锁和乐观锁,它们是多线程环境下确保数据一致性的重要手段。 【标签】:“求职面试 多线程” 【正文】: 悲观锁和乐观锁...

    面试必备之乐观锁与悲观锁.zip

    乐观锁和悲观锁是数据库事务控制...了解和掌握乐观锁与悲观锁的原理和应用场景,对于提升面试者的数据库管理技能和解决并发问题的能力至关重要。在面试中,深入探讨这些话题将有助于展示自己的专业水平和问题解决能力。

    数据库乐观锁与悲观锁1

    乐观锁与悲观锁各有优缺点。悲观锁适合于高并发写操作的场景,可以防止丢失更新,但可能导致死锁问题。乐观锁则适用于写操作较少,且可以接受偶尔的冲突重试的情况,它减少了锁的开销,提升了系统的吞吐量。然而,...

    面试必备之乐观锁与悲观锁.docx

    "面试必备之乐观锁与悲观锁" 在多线程编程中,锁机制是必不可少的一部分,锁机制可以防止多个线程同时访问共享资源,避免数据不一致和混乱的情况。锁机制可以分为悲观锁和乐观锁两种,下面我们将详细介绍这两种锁...

    面试资源乐观锁与悲观锁

    面试资源乐观锁与悲观锁

    JAVA架构面试专题_面试必备之乐观锁与悲观锁.pdf

    Java 架构面试中,乐观锁与悲观锁是两个重要的并发控制概念,它们在多线程环境下用于确保数据的一致性。理解这两种锁对于开发者来说至关重要,特别是在高并发的系统设计中。 **悲观锁**是一种保守的并发控制策略,...

    thinkPHP框架乐观锁和悲观锁实例分析

    除了上述的乐观锁和悲观锁实现技巧之外,ThinkPHP框架还提供了其他很多与数据操作和事务管理相关的功能和技巧。例如,在ThinkPHP中,可以使用事务控制相关的类和方法,如mysqli的transaction方法开始事务,commit...

    Hibernate乐观锁和悲观锁分析

    【Hibernate乐观锁与悲观锁详解】 在开发过程中,尤其是在并发环境下,确保数据的一致性和完整性至关重要。Hibernate,作为Java领域广泛使用的ORM框架,提供了一种处理并发数据访问冲突的手段,那就是锁机制。主要...

    面试必备之乐观锁与悲观锁.rar

    1. **事务隔离级别**:乐观锁和悲观锁与数据库的事务隔离级别密切相关。例如,读未提交(READ UNCOMMITTED)、读已提交(READ COMMITTED)、可重复读(REPEATABLE READ)和串行化(SERIALIZABLE)这四种隔离级别都会...

Global site tag (gtag.js) - Google Analytics