对方法使用声明式事务@Transactional,方法伪代码如下
@Transcational
public void method(){
...
synchronized (obj){
//修改某条数据状态为锁定状态
entity = mapper.select();
if(entity.status == 0){
entity.status = 1;
mapper.update(entity);
}
}
//其他操作
...
}
场景: 如锁定库中某条数据,使多线程竞争安全的情况下使用同步代码块
原因:线程A锁定操作的同步代码块已执行完成并继续进行其他操作时事务是未提交状态,线程B此时进入方法并进入同步代码块中,因线程A事务未提交,mysql默认隔离级别是可重复读,查询出的结果是未锁定状态,进行锁定就产生了重复锁定的问题。
解决方法:
1.将同步代码块范围扩大至方法结束
2.同步代码块内方法开启一个新事务,即@Transcational传播机制为REQUIRED_NEW,但需要注意事务aop嵌套问题
3.不使用数据库操作锁定数据 比如缓存锁定数据
4.将事务的隔离级别设置为读未提交(read uncommited ),此时就算未提交事务,在其他事务中读取该值也是修改后的状态