MYSQL使用锁解决并发下的更新丢失问题

更新丢失是指并发下两次更新同时进行,后一次更新覆盖了前一次更新的状况,更新丢失是数据没有保证一致性致使的。
举个栗子:mysql

  • 用户A在银行卡有100元钱,某一刻用户B向A转帐50元(称为B操做),同时有用户C向A转帐50元(称为C操做);
  • B操做从数据库中读取他此时的余额100,计算新的余额为100+50=150
  • C操做也从数据库中读取他此时的余额100,计算新的余额为100+50=150
  • B操做将balance=150写入数据库,以后C操做也将balance=150写入数据库
  • 最终A的余额变为150

上面的例子,A同时收到两笔50元转帐,最后的余额应该是200元,但却由于并发的问题变为了150元,缘由是B和C向A发起转帐请求时,同时打开了两个数据库会话,进行了两个事务,后一个事务拿到了前一个事务的中间状态数据,致使更新丢失。
经常使用的解决思路有两种:sql

  • 加锁同步执行
  • update前检查数据一致性

悲观锁

顾名思义,悲观锁在读取数据的时候都会认为会有别人去修改,因而在取数据的时候会对当前数据加一个锁,在操做结束前,不容许其他操做更改。要注意悲观锁和乐观锁都是业务逻辑层次的定义,不一样的设计可能会有不一样的实现。在mysql层经常使用的悲观锁实现方式是加一个排他锁。
排他锁
查阅资料不少对排他锁的解释是:“排他锁经过在事务中使用select xx for update语句来实现,排他锁会在当前行加一个行级锁,在当前事务提交前,其他事务没法进行update操做。”数据库

然而实际上并非这样,其实是加了排他锁的数据,在释放锁(事务结束)以前其余事务不能再对该数据加锁
排他锁之因此能阻止update,delete等操做是由于update,delete操做会自动加排他锁

也就是说即便加了排他锁也没法阻止select操做。而select XX for update 语法能够对select 操做加上排他锁。因此为了防止更新丢失能够在select时加上for update加锁 这样就能够阻止其他事务的select for update(但注意没法阻止select)
example:并发

begin;
select * from account where id = 1 for update;
update account set balance=150 where id =1;
commit;

这样在B操做提交前,C操做没法得到排他锁,从而避免对account的重复更新致使的更新丢失。设计

乐观锁

乐观锁是指在获取数据时候不加锁,乐观的认为操做不会有冲突,在update的时候再去检查冲突。
example:code

begin;
select balance from account where id=1;
-- 获得balance=100;而后计算balance=100+50=150
update account set balance = 150 where id=1 and balance = 100;
commit;

如上,若是sql在执行的过程当中发现update的affected为0 说明balance不等于100即该条数据有被其他事务更改过,此时业务上就能够返回失败或者从新select再计算事务

相关文章
相关标签/搜索