整合shiro问题--数据库事务失效

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。

@Autowired
    @Lazy
    private SysUserService userService;

文章作者: EvanZhou
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 EvanZhou !
 上一篇
Guava使用(一)Strings扩展 Guava使用(一)Strings扩展
Joiner字符串连接 // 跳过空值 String skipNulls = Joiner.on(",") .skipNulls() .join("张三", "李四", "王
2020-01-14
下一篇 
web应用认证概述 web应用认证概述
1 常见的认证方式1.1 Http Basic Auth每次请求都提供用户的用户名和密码。简单说 Basic Auth是配合Restful API 使用的最简单的认证方式,只需提供用户名密码即可,但是存在把用户名暴露给第三方客户端的风险,再
2019-12-19
  目录