Mysql,version~没变~,就是更新不成功,别慌!
@Transactional(timeout = 36000, rollbackFor = Throwable.class)
public void updateGoodNum(String id,Integer num)
throws Exception {
//1. select num as dbnum,version as dbversion from t where id=#{id}
//2. update t set num=dbnum-num,version =dbversion +1
// where id=#{id} and version =dbversion ;
// 如果更新失败,重试1,2部总共3回
}
我轻叹了口气,在mysql连接工具执行了,如下语句,将截图发给小航后,
隔离级别
| 隔离级别 | 说明 |
| READ UNCOMMITTED | 未提交读,会造成脏读,违反持久性D |
| READ COMMITTED | 读已提交数据, 会造成幻读 违反一致性C |
| REPEATABLE READ(RR) |
可重复读,默认隔离级别,
事务中的select 语句会读取事务开始前的快照,当然也能读到本事务的更新内容
|
| SERIALIZABLE | 不会使用mysql的mvcc机制,而是在每一个select请求下获得读锁,在每一个update操作下尝试获得写锁 |
表格模拟,为什么不行?
| 开始事务前 | 表t对应id=1的,version=1 | |
|
事务A
begin
|
事务B
begin
|
|
| 1 |
select version from t where id=1;
-- 得到version=1
|
update t set version=2 where id=1;
commit;
|
| 2 |
update t set XX where id=1 and version=1;
// 更新失败,update读取当前,version=2
|
|
| 3 |
select version from t where id=1;
// 得到version=1
|
|
| 4 | commit |
注意:事务中的select 是读快照,update是读当前。
解决方式
/// 如果更新失败,重试updateGoodNum总共3回
public AFacadeImpl{
@Autowired
AService aservice;
public void updateGoodsNum(){
boolean a = aservice.updateGoodNum(id,num);
if(!a){
a = aservice.updateGoodNum(id,num);
}
if(!a){
a = aservice.updateGoodNum(id,num);
}
}
}
public AServiceimpl implement AService{
@Transactional(timeout = 36000, rollbackFor = Throwable.class)
public boolean updateGoodNum(String id,Integer num)
throws Exception {
//1. select num as dbnum,version as dbversion from t where id=#{id}
//2. update t set num=dbnum-num,version =dbversion +1
// where id=#{id} and version =dbversion ;
/
}
}