乐观锁和悲观锁
无论是悲观锁还是乐观锁,都是人们定义出来的概念,可以认为是一种思想。其实不仅仅是关系型数据库系统中有乐观锁和悲观锁的概念,像memcache、hibernate、tair等都有类似的概念。
悲观锁是利用数据库本身提供的锁机制来实现的。
1、悲观锁
1)悲观:并发的事务都会相互影响,发生激烈的竞争
2)悲观锁的流程如下:
(1)在对任意记录进行修改前,先尝试为该记录加上排他锁(exclusive locking)。
(2)如果加锁失败,说明该记录正在被修改,那么当前查询可能要等待或者抛出异常。 具体响应方式由开发者根据实际需要决定。
(3)如果成功加锁,那么就可以对记录做修改,事务完成后就会解锁了。
(4)其间如果有其他对该记录做修改或加排他锁的操作,都会等待我们解锁或直接抛出异常。
代码示例:
//MySQL InnoDB中使用悲观锁:
//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的 那条数据就被我们锁定了,其它的事务必须等本次事务提交之后才能执行。
这样我们可以保证当前的数据不会被其它事务修改。
3)优点与不足
悲观并发控制实际上是“先取锁再访问”的保守策略,为数据处理的安全提供了保证。
但是在效率方面,处理加锁的机制会让数据库产生额外的开销,还有增加产生死锁的机会;
另外,在只读型事务处理中由于不会产生冲突,也没必要使用锁,这样做只能增加系统负载;
还有会降低了并行性,一个事务如果锁定了某行数据,其他事务就必须等待该事务处理完才可以处理那行数
2、乐观锁
1)乐观:认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。
2)实现方式:记录数据版本
(1)当读取数据时,将版本标识的值一同读出,数据每更新一次,同时对版本标识进行更新。
(2)当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的版本标识进行比对,如果数据库表当前版本号与第一次取出来的版本标识值相等,则予以更新,否则认为是过期数据。
代码示例:
//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};
3)优点与不足
乐观并发控制相信事务之间的数据竞争(data race)的概率是比较小的,因此尽可能直接做下去,直到提交的时候才去锁定,所以不会产生任何锁和死锁。
但如果直接简单这么做,还是有可能会遇到不可预期的结果,例如两个事务都读取了数据库的某一行,经过修改以后写回数据库,这时就遇到了问题。
上一篇: 乐观锁和悲观锁的区别
下一篇: MySQL数据库中视图与索引