解决javax.persistence.TransactionRequiredException: Executing an update/delete query的一种方法

解决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这句执行时会抛异常

在这里插入图片描述

解决方式:

  1. 在dao层不要单独使用@Modifying注解,同时也增加@Transactional注解,即可解决问题
  2. 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);
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值