spring事务管理
spring事务管理支持两种类型。一种是编程式的事务类型,另外一种是声明式的事务类型。但是无论哪一种底层都采用spring事务管理器进行统一管理。
spring事务管理介绍我之前写的还算比较详细:spring事务管理介绍
spring事务失效的原因
- 没有开启事务 @EnableTransactionManagement (如果使用springboot会自动配置开启该注解,注册事务管理器和事务增强器)
- 异常类型不对,spring事务默认只对RuntimeException进行回滚。
- 只能在作用在public方法上(SpringAOP基于代理的局限性)
- 子线程中无法使用事务,也就是你自己new出来的线程,异步执行的任务无法使用事务。
- 通过this调用当前类的方法。因为this调用是真实对象,并不是通过代理对象调用。例如:如果是一个不带事务的方法调用该类的带事务的方法,直接通过this.xxx()调用,而不生成代理事务。
- …
总结就是一句话:既然spring事务依赖于动态代理,那么事务能否失效,就开是否生成了代理对象。
springboot 整合shiro 事务失效了
如果你的项目整合了shiro,那么注意观察启动日志是否打印了类似于这样的语句:
Bean 'sysUser' of type [com.sun.proxy.$Proxy87] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
这句话的意思就是SysUser对象被提前初始化了,不会被spring后置处理器拦截处理,导致出现问题,例如不能够被自动代理。
如果你看明白了这句话,我想也大概明白了整合shiro时候为什么事务会失效了,因为spring事务依赖于AOP代理技术实现。
整合Shiro时候,你在自定义的Realm中自动注入了UserService,UserService在这里被提前初始化了,所以事务失效了。
具体原因:ShiroFilterFactoryBean实现了后置处理器接口,在加载bean后置处理器前会加载Configuration配置类,导致ShiroFactoryBean被初始化了,也就是在这里提前实例化了相关的bean。
ShiroFilterFactoryBean -> SecurityManager -> Realm实现类 -> UserService
解决办法
在自定义Realm的中注入UserService时候,使用懒加载@Lazy。