MySQL(十六)】更新丢失 解决方案

一个比较见的业务场景,先从表里读一条数据的一列,然后在内存中计算该列的新值,最后再update新值到表里:

select data from table where id = xxx; // db

newdate = data + 1; // 内存

update table set data = newdata where id = xxx; // db

这样的三条语句,如果不加事务,可能会有更新丢失的问题。就是多个事务并发修改同一行数据时,读到了相同的值,然后分别更新,那么就会丢失前一次更新;

为啥要分三条?直接update set data = data + 1貌似就行?

这里的+1只是示例,实际上这个1可能需要根据一些特定的业务逻辑计算出来,所以必须要先读到内存才能计算到新值;

怎么解决更新丢失问题?

这里介绍两种方案:

1.使用事务+锁定读

begin;

select data from table where id = xxx for update; // db

newdate = data + 1; // 内存

update table set data = newdata where id = xxx; // db

commit;

这里首先使用了begin语法,将上述三个步骤放入到事务中,并且读取时使用了for update的锁定读方式,这样一旦读到了数据,那么就会加X锁,别的事务便无法读该行数据或者修改该行数据了。

2.不使用事务,cas更新

// for loop begin
select data from table where id = xxx; // db

newdate = olddata + 1;// 内存

update table set data = newdata where id = xxx and data = olddata; // db
// for loop end

这个方案不需要事务,但是在update时,加上了cas的判断,整套逻辑需要放在循环中完成,不断cas尝试直到更新成功,需要业务逻辑来处理cas更新,并且可能需要设置最大重试次数,防止一直自旋;

貌似在高并发场景下,使用方案一更好些,毕竟方案二冲突的概率比较大,一直重复select update也会影响性能;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章