解决@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 />