错误使用锁和事务导致并发
在事务中添加锁来解决并发的问题,这并没有解决并发的问题。
@Transactional
@Override
public void execute(){
try {
lock.lock()// 开启锁
// 查询出数据
mapper.select();
// 根据查询出数据计算并写入到数据库中
mapper.udpate()
} finally {
lock.unlock()
}
}
比如数据库中count =100
- A线程进入当前语句执行,开启事务,获取锁,查询到count为100,扣减1,此时的count为99,锁释放,
- 此时B线程就能进入获取到锁,并且查询到数据count为100。A线程提交事务,此时数据库中的count为99
- B线程扣减1得到count为99,此时B线程将count值更新到数据库中,锁释放,提交事务
- 最后数据库得到count为99,但是执行了两次业务操作
这个原因是锁先释放掉了,但是事务没有提交,而mysql数据库库的隔离级别是可重复度,其他事务读取的数据未被改变的数据,读到的依旧是100。但锁被释放掉了时,其它线程立刻获取获取锁,此时读过来的数据还是原来的数据,导致该问题。
解决方式
加锁是为了让执行程序变成串行
- 将锁放到事务方面,让事务的执行变成串行就可以解决该问题。
- 数据库中串行的隔离级别也可以,就是在读数据时,添加了锁,其它事务在读取时,等待读锁。其实就是将并行变成了串行
@Service
public class A{
@Resource B b;
public void serviceA(){
try{
lock.lock()
b.serviceB();
} finally {
lock.unLock()
}
}
}
@Service
public class B{
@Transactional
public void serviceB() {
// 查询出数据
mapper.select();
// 根据查询出数据计算并写入到数据库中
mapper.udpate()
}
}