トランザクションをコミットし、手動で春をトランザクションをロールバック

  1.背景

  ベースエクスプレスパッケージピックアップ(ユーザがパッケージ情報データベース記憶ラップされます)、およびストレージ・パッケージシーン(データベースなどの郵便室及び貯蔵にパッケージ宅配パッケージ情報)、及びパッケージ情報と撮影情報記憶部彼らは、異なるデータベースに格納されています。会員ユーザがとるとき、2つのテーブルの更新情報(パーセル状況記憶テーブルとテーブルに挿入ピックアップピックアップ情報)する必要があります。

  問題の説明

  使用時にはSSMのバックエンドサービスを設定-timeフレームワーク、場合サービス層のビジネス・ロジックより複雑なビジネスロジックは、複数の呼ぶかもしれないDAOの変更データベースインターフェース層。この場合の使用春が来る@Transactionalトランザクション処理のための注釈を、ビジネスのニーズを満たすために困難になります。ブロックに示すように:

ブロック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コメントアノテーションデータベースをロールバックしないサービス、唯一のコントローラは、対応するエラーコードを返し層、次いで(例えば、0は、エラーデータベース記憶示す)コントローラ対応するエラーコード層に従ってデータベース削除操作を。プログラマ不適切な操作(おそらくプロセスを忘れてしまった)場合は、そのことは、データベースが不整合な状態になります。この目的のために、我々はより柔軟なトランザクション管理を採用する-使用してDataSourceTransactionManager手動トランザクション管理を。ブロック2に示すように:

ブロック2
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;// 入库失败(最大可能是数据库异常,由统一异常处理解决)
    }
}

  図2は、使用ブロックであるDataSourceTransactionManagerのコードブロック内のサービスの改善。改良されたコードをより柔軟になり、特定の状況に応じてバックデータベースに巻くことができます。

  3.付録:

  使用DataSourceTransactionManagerコードテンプレートデータベースのトランザクション管理を:

ブロック3
@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);
    }
}

おすすめ

転載: www.cnblogs.com/accumulating/p/11846726.html