你好,我是miniluo,今天我和你聊聊Spring声明式事务不生效的坑。java
下面就让我和你一块儿学习有哪些几种状况下Spring声明式事务不生效的坑。ide
没有正确理解@Transactional注解学习
你是否曾经写过和下文相似的代码?测试
@Service("productService")public class ProductServiceImpl implements IProductService {@Overridepublic void createProduct(Product product) {//此处可能会实现一些业务逻辑代码,判断是否知足建立产品的条件//请求内部方法建立产品 product.setProductName("Spring声明式事务"); executeCreateProduct(product); }@Transactionalprivate void executeCreateProduct(Product product){if(Objects.isNull(product)){throw new RuntimeException("没法建立空产品"); } product.create();//模拟出现异常期待事务回滚int zero = 1/0; }}
通过测试,咱们发现抛出了异常,但是产品仍是被建立了。缘由是,Spring 默认经过动态代理的方式实现 AOP,对目标方法进行加强,private 方法没法代理到,这么说咱们修改成public方法应该有效果。改完后再尝试发现产品仍是被建立。这里不得不说下@Transactional生效必须经过代理过的类从外部调用目标方法才能生效。知道这个缘由后,咱们把ProductServiceImpl以自身的方式注入,调整代码以下:this
@Service("productService")public class ProductServiceImpl implements IProductService {@Autowiredprivate ProductServiceImpl self;@Overridepublic void createProduct(Product product) {//此处可能会实现一些业务逻辑代码,判断是否知足建立产品的条件 product.setProductName("Spring声明式事务"); self.executeCreateProduct(product); //请求内部方法建立产品 }@Transactionalpublic void executeCreateProduct(Product product){if(Objects.isNull(product)){throw new RuntimeException("没法建立空产品"); } product.create();int zero = 1/0; //模拟出现异常期待事务回滚 }}
再次测试,咱们发现产品并无被建立,说明事务已生效,由于self 是由 Spring 经过 CGLIB 方式加强过的类。这种方式虽然能解决,可是并不建议这么作,而应该把@Transactional写在接口的实现方法上,建议把查询和更新(新增)分开。编码
异常处理不当致使事务失效spa
状况一:异常没法从方法传播出去,致使事务失效代理
@Service("productService")@Slf4jpublic class ProductServiceImpl implements IProductService {@Override@Transactionalpublic void createProduct(Product product) {//此处可能会实现一些业务逻辑代码,判断是否知足建立产品的条件 product.setProductName("Spring声明式事务");try { executeCreateProduct(product); //请求内部方法建立产品 }catch (Exception ex){ log.error("建立产品失败",ex); } }private void executeCreateProduct(Product product){if(Objects.isNull(product)){throw new RuntimeException("没法建立空产品"); } product.create();int zero = 1/0; //模拟出现异常期待事务回滚 }}
这种写法在实际编码中常犯的错误,若要使其生效,只需在catch中增长code
TransactionAspectSupport.currentTransactionStatus() .setRollbackOnly();
状况二:受检异常致使事务不生效
接口
@Service("productService") @Slf4j public class ProductServiceImpl implements IProductService { @Override @Transactional public void createProduct(Product product) throws IOException { //此处可能会实现一些业务逻辑代码,判断是否知足建立产品的条件 product.setProductName("Spring声明式事务"); executeCreateProduct(product); //请求内部方法建立产品 } private void executeCreateProduct(Product product) throws IOException { if(Objects.isNull(product)){ throw new RuntimeException("没法建立空产品"); } product.create(); Files.readAllLines(Paths.get("transaction-not-rollback")); } }
或许有这么个场景,这些代码并不是你写的,你并不知道外层或里面的业务逻辑实现,改动可能会有影响存量功能;这个时候咱们该怎么办呢?其实也不难,@Transactional已经为咱们给出了解决方案,只需将@Transactional调整为
@Transactional(rollbackFor = Exception.class)
至此,我和你一块儿回顾了平时编码过程当中常见的坑,下面再一块儿来看看关于事务传播性的坑。
事务传播性
咱们一块儿来看下面的两段代码,第一段是实现建立产品和产品上架。
@Service("productService") @Slf4jpublic class ProductServiceImpl implements IProductService {@Autowiredprivate IOfferService offerService;/** * 指望:产品的建立并不会因上架失败致使回滚 * @param product */@Override@Transactionalpublic void createProduct(Product product){//此处可能会实现一些业务逻辑代码,判断是否知足建立产品的条件 product.setProductName("Spring声明式事务"); executeCreateProduct(product); //请求内部方法建立产品if(Status.UPSHELVE.equals(product.getStatus())){ offerService.productUpShelve(product);//建立产品后,产品随即上架 } }private void executeCreateProduct(Product product) {if(Objects.isNull(product)){throw new RuntimeException("没法建立空产品"); } product.create(); }}
第二段是产品上架的实现。
@Service("offerService")public class OfferServiceImpl implements IOfferService {@Override@Transactionalpublic void productUpShelve(Product product) { product.upShelve();throw new RuntimeException("上架失败"); }}
咱们的指望是产品的建立成功与否不该该受到上架业务代码影响,咱们测试后发现,产品上架失败,致使建立产品回滚;这是什么缘由呢?这是由于建立产品的事务和产品上架的事务是同一个事务,因此上架失败天然会致使建立产品回滚。了解事务传播性的同窗都知道,咱们只须要在产品上架的方法配置事务的传播行为便可,告诉@Transactional,我是要本身独立事务
@Transactional(propagation = Propagation.REQUIRES_NEW)
好了,关于Spring声明式事务常踩的3个坑已经和你一块儿学习完,期待对你有所帮助和启发。
思考和讨论
一、文中咱们经过注入本身的方式解决了事务不生效的状况,请问可否使用this来完成呢?this.executeCreateProduct(product);
二、说到事务的传播行为,除了我所说的以外,还有哪些呢?
欢迎留言与我分享和指正!也欢迎你把这篇文章分享给你的朋友或同事,一块儿交流。
感谢您的阅读,咱们下节再见!
关注咱们的公众号,不定时分享技术、管理、业务等不一样领域的文章与您一块儿学习交流。也欢迎投稿:xiaouoron@foxmail.com