5

基本設定はすべて問題なく、トランザクションを試し始めました。Struts + Spring+Hibernateアノテーショントランザクションマネージャー。これはアクションのサンプルコードであり、サービスクラスを呼び出します。

    userService.addUser();

サービスクラスのaddUser()メソッドは次のとおりです。

    @Transactional(value="deu"  )
    public void addUser() {     
        userDao.addUser();
        this.addUser2();

    }

まず、addUseruserDaoを呼び出しました。これにより、ユーザーが挿入されます。次に、addUser2このサービスクラスの別のメソッドを呼び出しました。

    @Transactional(value="deu" , propagation=Propagation.REQUIRES_NEW  )
    public void addUser2()   {      
    //should be a new transaction and will not affect the previous one. 
            //this one will fail but should not affect the previous one.
        userDao.addUserFail();        
    }

そして、これはヌルPKのために失敗します。2番目の呼び出し(addUser2)は失敗すると思いますが、前の呼び出しには影響しません。ただし、ユーザーは挿入されません。

電話するだけの場合:

   @Transactional(value="deu"  )
    public void addUser() {     
        userDao.addUser();
        //this.addUser2();      
    }

それは機能しています。つまり、データベースなどの基本設定は間違っていません。

何か案が?

4

4 に答える 4

7

Springの宣言型トランザクション処理は、AOPプロキシを使用して機能します。tranasactional Beanを取得すると、実際には、Beanインスタンスをラップし、メソッド呼び出しをインターセプトし、必要に応じてトランザクションを開始し、実際のBeanのメソッドを呼び出し、必要に応じてトランザクションをコミットまたはロールバックするプロキシを取得します。

ただし、同じBean内の別のメソッドからBeanのメソッドを呼び出しているため、プロキシはバイパスされ、トランザクション動作を適用できません。

メソッドを別のBeanに配置するか、バイトコードをインストルメント化してBean内のメソッド呼び出しをインターセプトできるAspectJを使用します。

詳細な説明については、Springのドキュメントを参照してください。

于 2013-03-09T17:23:45.377 に答える
1

私はいくつかのテストを行い、結論を見つけました。

  1. 2番目のサービス(内部)が必要で例外をスローした場合、1番目のトランザクションでもそれをキャッチすると、両方がロールバックします(同じボートにいるためです!)

  2. 2番目のサービス(内部)がREQUIRES_NEWで例外をスローする場合、外部はこのロールバックを処理する必要があります(これは私のロールバックではありませんが、何かを行う必要があります)、それをキャッチしない場合、外部のこの例外は外部からロールバックをトリガーします(それは彼の例外ではありませんが、例外です!)。したがって、アウターはこの状況に対して何かをしなければなりません(ロールバックを設定するか、キャッチします)。

正しいですか?

于 2013-03-10T05:23:40.383 に答える
0

これは、SpringAOPアーキテクチャーによるものです。

Spring AOPはプロキシを使用するため、プロキシでメソッドを呼び出すときにアスペクトが実行されるだけです。

呼び出すときthis.addUser2(...)は、プロキシではなく、自己オブジェクトのメソッドを呼び出しています。したがって、アスペクトは実行されず、TX管理も行われません。

次のことができます。

  • addUser2メソッドを別のBean(たとえば)に移動してからUserService2、新しいBeanをに挿入し、UserServiceを使用してそのメソッドを呼び出しますuserService2.addUser2()
  • に注入UserServiceUserService(実行できるかどうかはわかりません)、notaddUser2()を使用してを呼び出します。userService.addUser2()this.addUser2()
于 2013-03-09T17:24:14.763 に答える
0

Amir Pashazadehが、同じBean内のトランザクションコンテキストでプロキシを呼び出す方法を知らないと言ったように、ここに例があります。

@Component
public class UserService(){     

    @Autowired @Setter private ApplicationContext  applicationContext;
    @Autowired @Setter private UserDao             userDao;

    @Transactional(value="deu"  )
    public void addUser() {     

        userDao.addUser();
        try{
           getProxy().addUser2();
        catch(Exception ex){
           // Avoid rolling back main transaction
           log("OMG it failed!!")
        }
    }

    @Transactional(value="deu" , propagation=Propagation.REQUIRES_NEW  )
    public void addUser2()   {      
    //should be a new transaction and will not affect the previous one. 
            //this one will fail but should not affect the previous one.
        userDao.addUserFail();        
    }

    private UserService getProxy() {
        return applicationContext.getBean(UserService.class); 
    }
}

addUser2で例外をキャッチしたが、トランザクションがすでにロールバックとしてマークされている場合、SpringはUnexpectedRollbackExceptionをスローするように見えることに注意してください。

于 2015-08-06T11:11:05.497 に答える