@Transactionalアノテーションは、理由と解決策を有効にしません
今日の作業で問題が発生しました。データを挿入する前に操作レコードを実行する必要があるため、操作レコードが後続の操作の影響を受けないことを考慮して、サービスレイヤーで呼び出された操作レコードを保存する方法。トランザクション伝播タイプは次のように設定されますREQUIRES_NEW
(現在のトランザクションが存在する場合は、現在のトランザクションを一時停止し、新しいトランザクションの実行を再開します。トランザクションのコミットまたはロールバックは前のトランザクションの影響を受けません)。テスト中に検出されました。 REQUIRES_NEWを設定した後も、操作レコードの保存方法が返されました。次のコードの影響を受け、次のコードでエラーが報告され、操作で記録されたトランザクションもロールバックされます。メソッドが呼び出されないためです。プロキシオブジェクトを介して、トランザクションはプロキシオブジェクトによって処理されず、@ Transactionalトランザクションは無効になります。
その時のシーンをシミュレートします。
データベースにuser1テーブルがあり、名前の長さは5で、サービスにはsaveメソッドとsaveLogメソッドがあり、saveメソッドでsaveLogメソッドが呼び出されます。
create table user1(
id int primary key auto_increment,
name varchar(5),
create_date datetime
);
サービス:
@Service
public class User1Service {
@Autowired
private User1Mapepr user1Mapepr; //mybaits的mapper
//这里传播行为声明为REQUIRED(如果当前没事务,创建事务,否则加入到当前事务)
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
public void save(){
//先保存记录
saveLog();
//后保存用户(这里会报错,因为name字段长度超过数据库规定的5字符)
user1Mapepr.save(new User1(null,"zs1111111111",new Date()));
}
//传播行为声明为REQUIRES_NEW(不管当前是否有事务,都创建新事务运行)
@Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class)
public void saveLog(){
//这里保存用户,能正常执行
System.out.println("saveLog");
user1Mapepr.save(new User1(null,"s1",new Date()));
System.out.println("=======保存成功=======");
}
}
実行後、トランザクション伝播動作はREQIREES_NEWですが、saveLogメソッドがプロキシオブジェクトを介して呼び出されないため、実行する新しいトランザクションが作成されないことがわかりました。そのため、@ Transactionalトランザクションは失敗します。
解決:
AopContextを介して現在のオブジェクトのプロキシオブジェクトを取得した後、saveLogメソッドを呼び出します
@Service
public class User1Service {
@Autowired
private User1Mapepr user1Mapepr;
@Autowired
private Service2 service2;
//这里传播行为声明为REQUIRED(如果当前没事务,创建事务,否则加入到当前事务)
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
public void save(){
//通过AopContext.currentProxy()获取当前对象的代理对象
User1Service aopService = (User1Service)AopContext.currentProxy();
//spring还为我们提供了AopUtils工具类
System.out.println("是否是aop对象===>"+AopUtils.isAopProxy(service));
System.out.println("是否是CGLIB===>"+AopUtils.isCglibProxy(service));
System.out.println("是否是JDK===>"+AopUtils.isJdkDynamicProxy(service));
//调用aop代理对象保存日志
aopService.saveLog();
user1Mapepr.save(new User1(null,"zs1111111111",new Date()));
}
//传播行为声明为REQUIRES_NEW(不管当前是否有事务,都创建新事务运行)
@Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class)
public void saveLog(){
//这里保存用户,能正常执行
System.out.println("saveLog");
user1Mapepr.save(new User1(null,"s1",new Date()));
System.out.println("=======保存成功=======");
}
}
実行後、後でユーザーのエラーを保存しても、saveLogトランザクションの実行には影響せず、@ Transactionalは正常に実行できます。