解决@Transactional事务在类内部方法调用不生效

代码示例


UserService测试接口类

package cn.sw.study.web.service;

/**

 * Created by shaowei on 2017/4/26.

 */

public interface UserService {

    void addInfo();

    void addOne();

}
UserServiceImpl测试实现类

package cn.sw.study.web.service.impl;

import cn.sw.study.web.dao.UserMapper;

import cn.sw.study.web.model.User;

import cn.sw.study.web.service.UserService;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;

import java.util.Date;

/**

 * 用户业务类

 * Created by shaowei on 2017/4/26.

 */

@Service("userService")

public class UserServiceImpl implements UserService{

    @Autowired
    UserMapper userMapper;

    public void addInfo() {
        addOne();

    }

    @Transactional
    public void addOne() {
        User record = new User();

        record.setLoginName("tom");

        record.setPwd("111111");

        record.setMobile("13913913913");

        record.setUsable(1);

        record.setCreateTime(new Date());

        userMapper.insertSelective(record);

        int i = 1/0;    // 测试事物的回滚

    }

}

现象描述


addInfo方法上没有事务注解,addOne方法上有事务注解,此时运行addInfo调用addOne方法,不会产生事务,测试数据遇到异常没有回滚。如果从外部类直接调用addOne方法,则事务是可以正常生效的。

解决方案


使用AopContext.currentProxy()来获取代理类再调用,如下

UserServiceImpl测试实现类

package cn.sw.study.web.service.impl;

import cn.sw.study.web.dao.UserMapper;

import cn.sw.study.web.model.User;

import cn.sw.study.web.service.UserService;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;

import java.util.Date;

/**

 * 用户业务类

 * Created by shaowei on 2017/4/26.

 */

@Service("userService")

public class UserServiceImpl implements UserService{

    @Autowired
    UserMapper userMapper;

    public void addInfo() {
        ((UserService)AopContext.currentProxy()).addOne();
    }

    @Transactional
    public void addOne() {
        User record = new User();

        record.setLoginName("tom");

        record.setPwd("111111");

        record.setMobile("13913913913");

        record.setUsable(1);

        record.setCreateTime(new Date());

        userMapper.insertSelective(record);

        int i = 1/0;    // 测试事物的回滚

    }

}

新问题


再次运行,如果没有添加expose-proxy="true"这个属性(暴露代理对象),则会报错

java.lang.IllegalStateException: Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available.

新问题解决:springboot中如何配置aop动态代理模式(转载自:http://tingcream.com/blogArticle/detail/fd08e233b37844bca556ee393e46a928


 

第一种方式:

在application.yml中有以下配置

spring:
  aop:
    #auto: true #默认为true,可省略
    proxy-target-class: true # 默认为false即JDK动态代理,我们一般要设为true,使用CGLIB代理

这种方式只能将代理模式修改为了CGLIG,但是不能设置暴露cglib代理的目标对象。

第二种方式:

在springboot启动类上标记这个注解

@EnableAspectJAutoProxy(exposeProxy=true,proxyTargetClass=true) 

同时,排除 AopAutoConfiguration.class的自动化配置

很好,这种方式同时设置exposeProxy为true和proxyTargetClass为true,即强制采用cglib代理,和暴露cglib代理的目标对象。

 

第三种方式:

 在springboot启动类上引入spring.xml配置文件

@ImportResource({"classpath:/spring.xml"})

同时,排除 AopAutoConfiguration.class的自动化配置

在spring.xml 配置文件中配置

  <!--1 aspectj 切面的支持 ,强制使用cglib,并暴露cglib代理的目标对象-->
      <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>  
      <context:annotation-config />  

posted @ 2021-03-26 17:53  ^^ITBOY^^  阅读(1020)  评论(0编辑  收藏  举报