解决javax.persistence.TransactionRequiredException: Executing an update/delete query的一种方法
代码中遇到的情况是这样的:controller层调用了service层一个方法A,service中调用了该类中另一个方法B,B方法加了@Async和@Transactional,B中调用了该类中另一个加了@Transactional注解的方法C,C中调用一个私有方法,对数据库数据进行更新操作,更新是通过@Query注解写的sql语句,也加了@Modifying,使用JPA。
代码情况大致如下:
controller层
@GetMapping(value = "/userInfo/{id}")
public void getUserInfo(@PathVariable("id") String id) {
userService.test(id);
System.out.println("ok");
}
service层
//相当于叙述中的方法A
@Override
public void test(String id) {
//do something
asyncSaveUser(id);
}
//相当于叙述中的方法B
@Async("pool")
@Transactional(rollbackFor = Exception.class)
@Override
public void asyncSaveUser(String id) {
try {
//do something
syncAccount(id);
} catch (Exception e) {
log.error("exception is", e);
}
}
//相当于叙述中的方法C
@Override
@Transactional(rollbackFor = Exception.class)
public void syncAccount(String id) {
//do something
modifyUser(id);
}
//相当于叙述中的私有方法
@Override
@Transactional(rollbackFor = Exception.class)
private void syncAccount(String id) {
//do something
userRepository.updateUpdateTimeById(id, System.currentTimeMillis());
//do something
}
dao持久层
@Repository
public interface UserRepository extends JpaRepository<User
, Serializable>
, JpaSpecificationExecutor<User> {
@Modifying
@Query(value = "UPDATE user_info " +
"SET update_time = :updateTime " +
"WHERE id = :id ", nativeQuery = true)
void updateUpdateTimeById(@Param("id") String id, @Param("updateTime") long updateTime);
}
此时调用该接口,在userRepository.updateUpdateTimeById这句执行时会抛异常
解决方式:
- 在dao层不要单独使用@Modifying注解,同时也增加@Transactional注解,即可解决问题
- asyncSaveUser方法中去掉@Transactional,获取本类的代理类来调用syncAccount方法,即可解决问题。
方法2的代码如下,需要先注入自己,或者用其他方法从spring容器里拿bean,然后调用原因的C方法,
@Lazy
@Resource
private UserService userService;
//相当于叙述中的方法B
@Async("pool")
//@Transactional(rollbackFor = Exception.class)
@Override
public void asyncSaveUser(String id) {
try {
//do something
userService.syncAccount(id);
} catch (Exception e) {
log.error("exception is", e);
}
}