最近活少,抽时间总结一些前阵子遇到的问题:使用了Spring事务(用@Transactional注解方式实现)后竟然没有正常回滚,这在线上可是很严重的问题,导致产生脏数据。如何排查并解决呢?这里提供三种思路以供参考:
本文测试代码场景:模拟给用户送优惠券操作:kafka异步送,接着预减优惠券库存,然后保存送券记录
情况一:Mysql层使用的是MYISAM存储引擎而不是INNODB
犯错率:1星
MYISAM不支持事务,INNODB支持事务处理,Mysql版本从5.5.8开始,默认使用INNODB存储引擎,如果你线上mysql版本高于这个,或者没有显式的设置存储引擎,这个问题一般不会出现。
解决方案:使用Mysql推荐的支持事务处理的INNODB存储引擎
情况二:显式的使用try{}catch(){}来捕获了异常
犯错率:4星
即使程序运行中间抛出了RuntimeException,但是被你catch吃掉了,于是程序继续往下执行,事务也就不能回滚了,代码如下:
解决方案:建议将try catch异常捕获放到最外层,即controller层
情况三:调用方法的对象不是aop代理对象
犯错率:5星
通过this.update()来减库存,this对象不是aop代理的对象,你可以通过ApplicationContextAware接口来获取代理类
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* 类描述:获取Spring代理类(上下文)
*/
public class ApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext apc;
public static ApplicationContext getApplicationContext() {
return apc;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.apc = applicationContext;
}
}
我自己碰到的就是情况三。希望对你有参考意义!