我们使用的 mongoD B4.0副本集 ,正常是支持事务操作的,但是开发运维两年
,某一次发生异常但是事务并没有回滚,导致数据对不上,意识到需要验证下事务是否还生效,单元测试验证 @Transactional 并未生效,查找原因,一开始以为是mongo的问题,但是两年前开始使用mongo就验证过了事务,一开始网络上找的答案都是如何配置,并未有效果,后来创建了个简单的项目,只引入相同版本spring data mongo 依赖事务生效,同时 @Async 线程异步 也生效。
同时对比了两个项目的输出日志 发现 测试 项目单元测试执行 会开启Transactional session,最后commit提交到数据库中 ,此阶段在Navicat客户端是查不到那条数据的,因为没有commit,但是 失效的项目 debug断住查看已经保存到数据库里了,不会回滚。
后来 感觉问题有三种可能
- 依赖冲突
- 改动过spring data mongo的源码 ,因为当时那个版本aggregate关联源码会报错,还有 保存string到数据库里是 ObjectId类型,不方便关联
- bean冲突
找问题 重新拉取了一样项目, 删减 依赖 改动源码 发现不是 这两个问题
然后只能一点一点删除配置的类 依赖 以及相关代码 最后发现 是shiro的问题
(此阶段 用了 两天)
就上网搜索 springboot + shiro 导致事物不生效的问题,后来找到几个博客,找到了答案
总结下来就是:
由于ShiroFilterFactoryBean实现了FactoryBean接口,所以它会提前被初始化。又因为SecurityManager,SecurityManager依赖于Realm实现类、Realm实现类又依赖于UserService,所以引发所有相关的bean提前初始化。
ShiroFilterFactoryBean -> SecurityManager -> Realm实现类 -> UserService
但是此时还只是ApplicationContext中registerBeanPostProcessors注册BeanPostProcessor处理器的阶段,此时AnnotationAwareAspectJAutoProxyCreator还没有注册到BeanFactory中,UserService无法享受到事务处理!
就是说在realm中注入的所有service都会提前加载,连带注入的service中,如果还有其他service注入也会提前加载,无法享受事务处理。
解决方案:
1.在realm中注入service时,加上@lazy注解
2.不在realm注入service
@Async 注解也需要 懒加载 ,要不可能会失效
希望可以帮助到你!