1.背景
ベースエクスプレスパッケージピックアップ(ユーザがパッケージ情報データベース記憶ラップされます)、およびストレージ・パッケージシーン(データベースなどの郵便室及び貯蔵にパッケージ宅配パッケージ情報)、及びパッケージ情報と撮影情報記憶部彼らは、異なるデータベースに格納されています。会員ユーザがとるとき、2つのテーブルの更新情報(パーセル状況記憶テーブルとテーブルに挿入ピックアップピックアップ情報)する必要があります。
問題の説明
使用時にはSSMのバックエンドサービスを設定-timeフレームワーク、場合サービス層のビジネス・ロジックより複雑なビジネスロジックは、複数の呼ぶかもしれないDAOの変更データベースインターフェース層。この場合の使用春が来る@Transactionalトランザクション処理のための注釈を、ビジネスのニーズを満たすために困難になります。ブロックに示すように:
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に示すように:
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コードテンプレートデータベースのトランザクション管理を:
@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);
}
}