有如下表:
select * from tt;
+----+-------+
| id | value |
+----+-------+
| 1 | 1 |
+----+-------+
有如下方法:
@Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
public int increAndGet(int id){
incre(id);
return get(id)
}
@Update("update tt set value=value+1 where id=#{id}")
public void incre(int id);
@Select("select value from tt where id=#{id}")
public int get(int id);
请问上述方法有线程安全问题么?
比如两个线程同时执行 increAndGet(1),有没有可能都返回3呢?
会不会如下执行呢?
value | 线程1 | 线程2 |
---|---|---|
1 | ||
2 | update tt set value=value+1 | |
3 | update tt set value=value+1 | |
3 | select value from tt | |
3 | select value from tt |
答案是否定的,因为increAndGet开启了事务,并且update语句会加锁,但是释放锁并不是执行完updat后立刻释放,而是在整个事务提交时释放,所以第二个线程执行incre时会被阻塞,直到第一个线程从increAndGet方法返回,线程二才能从incre方法返回继续执行。
事务在需要加锁时加锁,但直到事务提交时才释放锁,这就是两阶段锁协议。