赞
踩
一个比较见的业务场景,先从表里读一条数据的一列,然后在内存中计算该列的新值,最后再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也会影响性能;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。