MySQL 乐观锁和悲观锁
前言
1)在数据库的锁机制中介绍过,数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和一致性以及数据库的一致性。
2)加锁是为了解决更新丢失问题
更新丢失
两次更新同时进行,后一次更新覆盖了前一次更新的情况,更新丢失是数据没有保证一致性导致的。
------事务A查询余额,此时balance=100------- select balance from account where id = '1'; ------事务B查询余额,此时balance=100------- select balance from account where id = '1'; ------事务A充值100,此时num=200------- update account set balance = balance + 100 where id = 1; ------事务B消费30,此时num=70------- update account set balance = balance - 30 where id = 1;
由于A、B是同时进行的,造成了事务A被事务B覆盖了。
解决办法
1)加锁同步执行
2)update时检查
乐观并发控制(乐观锁)
1)假设数据不会发生冲突,只在提交操作时检查是否违反数据完整性。
2)乐观锁一般是为数据增加一个版本标识实现。
------事务A查询余额,此时balance=100,version=1------- select balance,version from account where = '1'; ------事务B查询余额,此时balance=100,version=1------- select balance,version from account where id= '1'; ------事务A充值100,此时num=200------- update account set balance = balance + 100,version = version + 1 where id = 1 and version = 1; ------事务B消费30,此时失败------- update account set balance = balance - 30,version = version + 1 where id = 1 and version = 1;
优点与不足
- 乐观锁在失败回滚的开销较大
悲观并发控制(悲观锁)
1)假定数据会发生冲突,屏蔽一切可能违反数据完整性的操作。
2)悲观锁一般利用mysql的排它锁实现。
------事务A查询余额,此时balance=100并为id=1加锁------- select balance from account where id = '1' for update; ------事务B查询余额,此时无法加锁失败------- select balance from account where id = '1' for update; ------事务A充值100,此时num=200------- update account set balance = balance + 100 where id = 1;
优点与不足
- 悲观锁采用一锁二查三更新的严谨策略。
- 加锁产生额外的开销,容易产生死锁;
- 一个事务中锁定了某行数据,其他事务将等待。