@Transactional是通过使用AOP,在目标方法执行前后进行事务的开启和提交。所以,Lock锁住的代码,其实并没有包含住一整个事务!
解决方法
- 使用编程式事务
//加锁
lock.lock();
// 编程式事务
TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
.....
// 在锁中提交
transactionManager.commit(status);
- @Transactional单独一个方法
@RestController
@RequestMapping("/up")
public class UpController {
@Resource
private UpService upService;
@RequestMapping("/test")
public void test() throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(10);
for (int i = 0; i < 10; i++) {
new Thread(() -> {
for (int j = 0; j < 10; j++) {
upService.test();
}
countDownLatch.countDown();
}).start();
}
countDownLatch.await();
System.out.println("结束");
}
}
public interface UpService {
void test();
void test1();
}
@Service
public class UpServiceImpl implements UpService {
@Resource
private NewtableMapper newtableMapper;
@Resource
@Lazy
private UpService upService;
private Lock lock = new ReentrantLock();
public void test() {
try {
lock.lock();
upService.test1();
} finally {
lock.unlock();
}
}
@Transactional
public void test1(){
// 查询id为99的数据
QueryWrapper<Newtable> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(Newtable::getId, 99);
Newtable newtable = newtableMapper.selectOne(wrapper);
//将id为99的数据的level-1
Newtable newtable1 = new Newtable();
newtable1.setId(99);
newtable1.setLevel(newtable.getLevel() - 1);
newtableMapper.updateLevel(newtable1);
}
}
public interface NewtableMapper extends BaseMapper<Newtable> {
void updateLevel(Newtable newtable);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.asiainfo.audit.mapper.NewtableMapper">
<resultMap id="BaseResultMap" type="com.asiainfo.audit.po.Newtable">
<result property="id" column="id" jdbcType="INTEGER"/>
<result property="level" column="level" jdbcType="INTEGER"/>
</resultMap>
<sql id="Base_Column_List">
id,level
</sql>
<update id="updateLevel" parameterType="com.asiainfo.audit.po.Newtable">
update newtable set level = #{level} where id = #{id}
</update>
</mapper>
@TableName(value ="newtable")
@Data
public class Newtable implements Serializable {
/**
*
*/
@TableField(value = "id")
private Integer id;
/**
*
*/
@TableField(value = "level")
private Integer level;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}