【踩坑】Shiro和Mybatis整合,事务失效 will not be managed by Spring

[速记] 踩坑

今天一下午都在找这个bug,发现平时用的好好的mybatis,居然突然就事务失效了、
当然我想大家第一反应就是@Transaction注解的一些注意要点,这些我也简单在这贴一下吧:
spring管理的事务,其实就是靠aop来对数据库操作方法的前后进行处理。
我理解的spring做的事情如下:
spring织布机前后织入了逻辑(生成类的代理对象)

public void springAop(){

//1. 获取连接,设置事务为手动提交
try{
//2. 执行业务代码
excute();
}catch(Exception e){
  //回滚
}
//提交
}

所以我们理解为怎么让aop生效就可以了

  1. 自然需要spring管理,所以需要加上@Service或者@Component注解
  2. 自然需要spring反射调用,所以方法必须为public,不能为final
  3. 这个调用的过程必须能被切点pointcut捕捉到,所以this对象自己调用自己的方法是不会被aop捕捉到的
对于事务,有接口实现类A,有方法a1和a2, 和接口实现类B有方法b1和b2
1. 如果方法不是public修饰,无法使用事务
2. 如果不能使用aop代理,比如设置final关键字的类
3. 如果其他接口通过aop调用a1,a1有事务,则事务有效,不管a1内部调用或外部调用其他方法
4. 如果其他接口通过aop调用a1,a1没有事务,a1调用a2,a2有事务,事务不生效.
5. 如果其他接口通过aop调用a1,a1有事务,a1调用a2,a2抛出异常,a1或a2去try catch,事务不生效
6. 如果其他接口通过aop调用a1,a1有事务,a1调用b1,默认的话b1会因为REQUIRED传播机制,进入到a1的事务中,事务生效
7. 如果其他接口通过aop调用a1,a1有事务,a1调用b1,b1抛出异常,a1捕捉异常,事务生效会回滚,但是会抛出异常`Transaction rolled back because it has been marked as rollback-only`,
这是因为因为B已经抛出异常了,B所在的事务是REQUIRED,也就是会加入A的事务,导致A的事务是标记回滚状态的,A try catch 内部处理了异常,
会执行提交操作,但是提交标记了回滚异常的会导致最终回滚
**解决方法: A继续抛出异常,或者B内部try catch 或者B开启新事务**

回到正题

好了对于经常使用spring和aop的人来说,我上面说的都是废话,重要的来了,我怎么排查原因都还是事务失效,甚至一度认为是mybatis-plus升到3.x的锅,因为我之前项目用的2.x,还特地降级再试发现还是一样。

最后想到什么问题都可以从日志中解决,所以我把日志等级设置为debug
同时开启了mybatis的日志打印

mybatis-plus:
	  #原生配置
  configuration:
  	log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

然后我看到了这条信息
在这里插入图片描述
what???这个jdbc连接没有被spring接管?我要的就是spring的事务啊,所以大概就是这里出问题了。
最后尝试网上各种方法无果,最后看到一个博客,附上连接:
SpringBoot+Shiro引起事务失效、错误原因、解决方法
一看,大概意思就是我的Shiro中,reaml类里面使用了UserService等依赖对象,这个时候它会比spring一般的初始化实例要早,而spring的实例都是单例的,也就是上面的spring织布机还没来得及把前后处理事务的代码织入进去,shiro初始化就把这两个类的代理对象生成了,而对象只会实例化一次,所以就出现那条

JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@2af8253a] will not be managed by Spring

解决办法原博客也提出来了
要么在reaml类中使用mapper接口
要么使用@lazy指定懒加载

问题解决

发布了145 篇原创文章 · 获赞 193 · 访问量 59万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章