Spring事务失败的8个原因,这次你可以扇面试官一巴掌:挂了,我会陆续更新的。。。)stackmanager前几天不是发过一篇文章,里面有个事务失败的问题:What使用Spring的@Transactional注解控制事务时场景不生效?其中一位热心粉丝留言分享,觉得总结有些心得,所以放在最上面:但是我觉得总结的不够完整,今天再总结一下,然后跟着粉丝总结对其进行补充和完善。不用说,我确定我没有一个完整的总结,但我希望它能帮助有需要的人。1.数据库引擎不支持事务。这里以MySQL为例。它的MyISAM引擎不支持事务操作。InnoDB是支持事务的引擎。一般使用InnoDB来支持事务。根据MySQL官方文档:https://dev.mysql.com/doc/refman/5.5/en/storage-engine-setting.html从MySQL5.5.5开始默认的存储引擎是:InnoDB,之前默认是:MyISAM,所以值得注意的是底层引擎是不支持事务的,你怎么弄也没用。2、不被Spring管理,如下例所示://@ServicepublicclassOrderServiceImplimplementsOrderService{@TransactionalpublicvoidupdateOrder(Orderorder){//updateorder}}如果此时注释掉@Service注解,则该类不会被加载为一个Bean,那么这个类就不会被Spring管理,事务自然会失败。3.方法不公开。以下摘自Spring官方文档:使用代理时,只应将@Transactional注解应用于具有公共可见性的方法。如果您使用@Transactional注释对受保护的、私有的或包可见的方法进行注释,则不会引发错误,但注释的方法不会显示已配置的事务设置。如果您需要注释非公共方法,请考虑使用AspectJ(见下文)。大概意思就是@Transactional只能用在public方法上,否则transactions是不会失败的。如果你想在非公共方法中使用它,你可以启用AspectJ代理模式。4、我们来看两个自调用问题的例子:@ServicepublicclassOrderServiceImplimplementsOrderService{publicvoidupdate(Orderorder){updateOrder(order);}@TransactionalpublicvoidupdateOrder(Orderorder){//updateorder}}update方法没有添加@Transactional注解,以及调用有@Transactional注解的updateOrder方法,updateOrder方法上的事务是否起作用?我们看下面的例子:@ServicepublicclassOrderServiceImplimplementsOrderService{@Transactionalpublicvoidupdate(Orderorder){updateOrder(order);}@Transactional(propagation=Propagation.REQUIRES_NEW)publicvoidupdateOrder(Orderorderate){//upd}}这一次,@Transactional被添加到update方法,并在updateOrder中添加了REQUIRES_NEW以启动新事务。新开的交易有效吗?这两个例子的答案是:不!因为调用的是自己,调用的是这个类本身的方法,不经过Spring的代理类,默认只有在外部调用事务时才会生效。这也是一个经常被人津津乐道的经典问题。解决方法之一是将自己注入到类中,并使用注入的对象调用另一个方法。这不优雅。另一个可行的方案可以参考这篇文章《Spring 如何在一个事务中开启另一个事务?》。5.数据源没有配置事务管理器@BeanpublicPlatformTransactionManagertransactionManager(DataSourcedataSource){returnnewDataSourceTransactionManager(dataSource);}如上图,如果当前数据源没有配置事务管理器,是没用的!6.不支持事务看下面的例子:@ServicepublicclassOrderServiceImplimplementsOrderService{@Transactionalpublicvoidupdate(Orderorder){updateOrder(order);}@Transactional(propagation=Propagation.NOT_SUPPORTED)publicvoidupdateOrder(Orderorder){//updateorder}}Propagation.NOT_SUPPORTED:表示没有事务操作,如果当前挂掉。他们都主动不支持事务操作,所以事务生效也没用!7、异常被吃掉的场景有很多://@ServicepublicclassOrderServiceImplimplementsOrderService{@TransactionalpublicvoidupdateOrder(Orderorder){try{//updateorder}catch{}}}把异常吃掉,然后又不抛出,事务怎么滚后退!8.异常类型错误上面的例子又抛出了一个异常://@ServicepublicclassOrderServiceImplimplementsOrderService{@TransactionalpublicvoidupdateOrder(Orderorder){try{//updateorder}catch{thrownewException("Updateerror");}}}这种事务也是无效的,因为默认回滚是:RuntimeException,如果要触发其他异常的回滚,需要在注解上进行配置,如:@Transactional(rollbackFor=Exception.class)这个配置仅限于Throwable异常类及其子类。小结本文总结了八种事务失败场景。其实最常见的情况是自调用、异常被吃掉、异常抛出类型错误。正如文章开头所说,本文不一定总结一切,只是总结了常见的事务失败场景。即便如此,这8点也足以帮你打败面试官。如果你知道其他场景,欢迎留言分享。点击下方了解更多链接关注Java技术栈,栈长会持续分享有趣的Java技术。
