mysql-mysql悲观锁和乐观锁

时间:2023-03-08 16:06:26

1、mysql的四种事务隔离级别
I. 对于同时运行多个事务,当这些事务访问数据库中的相同数据时,如果没有采取必要的隔离机制,就会导致各种并发问题。
   (1)脏读: 对于两个事物 T1, T2, T1 读取了已经被 T2 更新但还没有被提交的字段. 之后, 若 T2 回滚, T1读取的内容就是临时且无效的.
   (2)不可重复读: 对于两个事物 T1, T2, T1 读取了一个字段, 然后 T2 更新了该字段. 之后, T1再次读取同一个字段, 值就不同了.
(3)幻读: 对于两个事物 T1, T2, T1 从一个表中读取了一个字段, 然后 T2 在该表中插入了一些新的行. 之后, 如果 T1 再次读取同一个表, 就会多出几行.
  
II.数据库事务的隔离性:数据库必须的隔离并发运行多个事务的能力,使它们不会相互影响,避免各种并发问题。
  
   III.隔离级别:一个事务与其它事务的隔离程度称为隔离级别,数据库规定了多种隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数扰一致性就越好,但并发性也就越弱。
   (1)读未提交数据,允许事务读取未被其它事务提交的变更,上面三个问题都会出现。
   (2)读已提交数据,允许事务读取被其它事务提交的变理,避免脏读,但会出现不可重复读和幻读。
(3)可重复读,确保一个事务可以从一个字段读取相同的值,在此事务持续期间,禁止其它事务操作该字段,幻读问题仍存在
(4)串行化,效率低
  
IV.mysql默认的隔离级别是可重复读,设置数据库隔离级别有两种方式
   (1)使用Sql语句修改数据库的隔离级别。
   (2)在 Hibernate 中设置隔离级别
    READ UNCOMMITED
   READ COMMITED
    REPEATABLE READ
SERIALIZEABLE

2、mysql悲观锁

只有执行select * from table for update语句时,才会执行mysql的悲观锁,
要使用悲观锁,我们必须关闭mysql数据库的自动提交属性,因为MySQL默认使用autocommit模式,
也就是说,当你执行一个更新操作后,MySQL会立刻将结果进行提交。

(1)mysql的锁级别,Row Lock和Table Lock ,mysql的默认锁级别是Row-Level Lock
表A有三个字段 id , name, age,其中id为主键,name有索引,age为普通字段
a.执行select * from A where id=1 for update
这种情况会锁row
b.执行select * from A where name=1 for update
这种情况会锁row
c.执行select * from A where age=1 for update
这种情况会锁表

(2)悲观锁,它指的是某一事务,对数据被另一事务的修改持保守态度,即,每次查询的时候就会锁定记录或锁定表,直到修改完成
需要注意的是,如果事务A执行了select * from A where id = 3 for update ,则B事务如果执行
select * from A where id = 3 for update则要等待A事务结束后才会执行
3、mysql乐观锁
(1)概念:
乐观锁假设认为数据一般情况下不会造成冲突所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,
如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。
(2)实现方式
方式一:
使用数据版本(Version)记录机制实现,将version字段的值一同读出,数据每更新一次,对此version值加一。
当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,
如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据
方式二:
需要乐观锁控制的table中增加一个字段,名称无所谓,字段类型使用时间戳(timestamp),
和上面的version类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,
如果一致则OK,否则就是版本冲突。
4、悲观锁使用场景举例
有两张表,一张货物表goods,一张用户表account,账户表有用户名和用户钱数
不使用锁的情况下:
(1)A用户查询goods表,发现货物还剩一件,然后A用户执行付款操作,此时,B用户也发现goods表还有一件,也执行付款操作,
(2)B的动作比A快,此时B付完款,goods表减1,此时A也付完款了,发现货物没了,所以就有问题
联想到事物一个使用场景,
A访问表,修改goods表的剩余量,是一个事物,
A付款是一个事物,保证两个事务都完成,或者都完不成,两个小事务要运行在一个大事务里面

5、悲观锁和乐观锁的总结
乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,
加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行retry,
这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。