• Spring手动提交事务和回滚事务


      1. 背景介绍

      本文基于快递包裹取件(用户获取包裹并将包裹信息存储数据库)和包裹入库(快递员将包裹放入收发室并将包裹信息存储如数据库)场景,并将包裹入库信息和取件信息分别存入不同的数据库。这样当用户取件时,需要更新两个表信息(入库表中的包裹状态和取件表中插入取件信息)。

      2. 问题描述

      在采用SSM框架搭建后端服务时,若Service层业务逻辑较复杂,一条业务逻辑中可能会调用多个dao层更改数据库的接口。此时若采用Spring自带的@Transactional注解进行事务处理,将难以满足业务需求。正如代码块1所示:

    代码块1
    packet com.example.pickup;
    public interface PickUpDao{
        @Delete("delete from pickup where orderNum=#{orderNum}")
        public int removePickUpPacket(String orderNum)
    }
    
    packet com.example.storage;
    public interface StorageDao{
        @Update("update storage set isPickup=false where orderNum=#{orderNum}")
        public int updateStatuOfStoragePacket(String orderNum,boolean statu)
    }
    
    packet com.example.pickup;
    public class PickUpServiceImpl{
        @Autowired
        private PickUpDao pickUpDao;
        @Autowired
        private StorageDao storageDao;
        
        @Transactional(readOnly=false)
        public int addPickUpPacket(PickUp pickUp){
            boolean isAlreadyPickUp=pickUpDao.getPickUpPacket(pickup.getOrderNum())==null?false:true;
            if(isAlreadyPickUp){
                return 3;// 表示该包裹已经取件
            }
           	Integer res1=dao.addPickUpPacket(pickUp);
            if(res1!=0){
               Integer res2=storageDao.updateStatuOfStoragePacket(pickUp.getOrderNum(),true);
                if(res2!=-1){
                    return 2;// 表示取件成功
                }else{
                    return 0; //①
                }
            }
            return 0;// 入库失败(最大可能是数据库异常,由统一异常处理解决)
        }
    }
    

      如代码块1所示,在代码行①的位置,更新入库包裹状态出错(可能是因为包裹入库信息被删除)。此时程序应该回滚数据库(包括对取件表的回滚)。但采用@Transactional注解注释后的服务不会回滚数据库,只会向Controller层返回相应的错误码(如0表示数据库入库出错),然后再由Controller层根据相应的错误码进行数据库删除操作。若程序员操作不当(可能是忘记处理),会使得数据库处于一种不一致状态。为此,本文将采用一种更为灵活的事务管理方式—采用DataSourceTransactionManager进行手动事务管理。如代码块2所示:

    代码块2
    ```java packet com.example.pickup; public class PickUpServiceImpl{ @Autowired private DataSourceTransactionManager transactionManager; TransactionStatus transactionStatus = null;
    @Autowired
    private PickUpDao pickUpDao;
    @Autowired
    private StorageDao storageDao;
    
    public int addPickUpPacket(PickUp pickUp){
        transactionStatus=transactionManager.getTransaction(new 				DefaultTransactionDefinition());
        boolean isAlreadyPickUp=pickUpDao.getPickUpPacket(pickup.getOrderNum())==null?false:true;
        if(isAlreadyPickUp){
            return 3;// 表示该包裹已经取件
        }
       	Integer res1=dao.addPickUpPacket(pickUp);
        if(res1!=0){
           Integer res2=storageDao.updateStatuOfStoragePacket(pickUp.getOrderNum(),true);
            if(res2!=-1){
                ransactionManager.commit(transactionStatus);
                return 2;// 表示取件成功
            }else{
                transactionManager.rollback(transactionStatus);//回滚数据库(两张表均回滚)
                return 0;
            }
        }
        return 0;// 入库失败(最大可能是数据库异常,由统一异常处理解决)
    }
    

    }

    
    &emsp;&emsp;代码块2是采用<font face="Times New Roman">DataSourceTransactionManager</font>对代码块1中服务的改进。改进后的代码将更加灵活,可根据具体情况对数据库进行回滚。
    
    #### &emsp;&emsp;3. 附录:
    
    &emsp;&emsp;采用<font face="Times New Roman">DataSourceTransactionManager</font>进行数据库事务管理的代码模板:
    
    <center>代码块3</center>
    
    ```java
    @Autowired
    private DataSourceTransactionManager manager;
    
    TransactionStatus status = null;
    
    public void method(){
        status=manager.getTransaction(new DefaultTransactionDefinition());
        try{
          //dosomething
          manager.commit(transactionStatus);
        }catch(Exception ex){
          manager.rollback(transactionStatus);
        }
    }
    
  • 相关阅读:
    Spring boot 启动图片
    Spring Cloud 从入门到入门
    理解错误的 Arrays.asList()
    git github 对代码的管理
    【POJ 2154】Color
    CodeForces
    CodeForces
    CodeForces
    CodeForces
    [数据结构]Hash Table(哈希表)
  • 原文地址:https://www.cnblogs.com/accumulating/p/11846726.html
Copyright © 2020-2023  润新知