4

トランザクション境界に関連する問題があり、何が問題なのかわかりません。

@Transactional( propagation = Propagation.REQUIRED )
Class A {
void methodA() {
     try {
     new B().callMethodB(obj)
     } catch(Exception e) {
           updateSomeProperty(obj1)
     }
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
void updateSomeProperty(Object obj1) {
     obj1.setProperty(1);
     obj1.save();       
}
        }

 Class B {

   public void callMethodB(Object obj) throws Exception {
    throws new Exception();  
 }

 }

問題は、エラーがスローされたときにオブジェクトが更新されていないことです。メソッド内から SQL コードを実行しようとしましupdateSomePropertyたが、これも機能しませんでした。

基本的に、例外がスローされたかどうかにかかわらず、オブジェクトのプロパティを更新したいと考えています。
何か案は ??

4

5 に答える 5

3

そして、それはうまくいかないはずです。クラスの別のメソッドから updateSomeProperty(obj1) を呼び出し、デフォルトのトランザクション動作を変更しようとするため (REQUIRED から REQUIRED_NEW に)。しかし、うまくいきません。そのため、例外が発生するとすべての変更がロールバックされます。

デフォルトでは、Spring はインターフェイスのプロキシを作成し、@Transactional アノテーションは public メソッドにのみ使用する必要があります。そして、このメソッドは「外部」から呼び出す必要があります。クラス内の別のメソッドからそれらを呼び出す場合、@Transactional アノテーションは機能しません。

xml でトランザクションのデフォルト設定を変更することもできます (プロパティ proxy-target-class および mode を参照)。しかし、私はこれを変更したことがなく、正確にどのように機能するかを覚えていません。

<tx:annotation-driven transaction-manager="txManager" mode="..." proxy-target-class="..."/>

編集:

ところで。これは、トランザクションの落とし穴に関する非常に優れた記事です。とても助かりました。トランザクションに関する他の非常に興味深い記事もいくつかあります。

編集2:

またあったね。私はあなたの問題の解決策を見つけると思います. 少なくとも私はこれをテストしましたが、うまく機能します。トランザクション モードを「AspectJ」に変更し、AspectJ コンパイル タイム ウィービングをプロジェクトに使用することを提案しました。これにより、トランザクションの動作を変更して、1 つのクラス内の別のメソッドからプライベート トランザクション メソッドを呼び出すことができます (開始されたネストされたトランザクションの場合)。このような場合、ネストされたトランザクションでいくつかの変更をコミットできますが、外側のトランザクションはロールバックされます。このためには、次の手順を実行する必要があります。

1) トランザクション定義でトランザクション モードを変更します。 - xml 構成を使用する場合:

<tx:annotation-driven transaction-manager="txManager" mode="aspectj"/>
  • Java構成を使用する場合:

    @EnableTransactionManagement(mode=AdviceMode.ASPECTJ, proxyTargetClass=false)

2) aspectj の依存関係を pom に追加します。

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>${aspectj.version}</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>${aspectj.version}</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjtools</artifactId>
    <version>${aspectj.version}</version>
</dependency>

3) pom に spring-aspects の依存関係を追加します。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>3.1.2.RELEASE</version>
    <scope>compile</scope>
</dependency>

4) コンパイル時のウィーブを有効にする Maven プラグインを追加します。

        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>1.4</version>
            <configuration>
                <showWeaveInfo>true</showWeaveInfo>
                <source>${compiler.version}</source>
                <target>${compiler.version}</target>
                <Xlint>ignore</Xlint>
                <complianceLevel>${compiler.version}</complianceLevel>
                <encoding>UTF-8</encoding>
                <verbose>false</verbose>
                <aspectLibraries>
                    <aspectLibrary>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-aspects</artifactId>
                    </aspectLibrary>
                </aspectLibraries>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                        <!-- <goal>test-compile</goal> -->
                    </goals>
                </execution>
            </executions>
            <dependencies>
                <dependency>
                    <groupId>org.aspectj</groupId>
                    <artifactId>aspectjrt</artifactId>
                    <version>${aspectj.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.aspectj</groupId>
                    <artifactId>aspectjtools</artifactId>
                    <version>${aspectj.version}</version>
                </dependency>
            </dependencies>
        </plugin>

5) また、pom に maven コンパイラ プラグインがあるため、追加する方がよいと思います。

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <compilerVersion>${compiler.version}</compilerVersion>
        <fork>true</fork>
        <source>1.7</source>
        <target>1.7</target>
    </configuration>
</plugin>

*注: jdk バージョン 1.7 以降を使用しています。そして、私のコンパイラとaspectjのバージョンはsushです:

<compiler.version>1.7</compiler.version>
<aspectj.version>1.6.12</aspectj.version>

また、他のライブラリのそのようなバージョンもあります(ただし、これは必要ではないと思います):

<org.springframework.version>3.1.0.RELEASE</org.springframework.version>
<org.hibernate.version>4.1.0.Final</org.hibernate.version>
<org.springdata.version>1.0.2.RELEASE</org.springdata.version>

春にロードタイムウィーブを使用することもできますが、構成がより難しく (これは私の意見です)、本番環境での使用はお勧めしません (いくつかの投稿で読んだように)。しかし、それを使用することに決めた場合は、Web および春の参照ドキュメントで多くの情報を見つけることができます。

Maven なしでコンパイル時のウィーブを使用したい場合、これを構成する方法がわかりません。(私はmavenでのみテストしました)。Web でそのような情報を見つけようとすることはできますが、maven を使用すると依存関係を処理するのがはるかに簡単になるため (この例の場合、必要なプラグインを追加すること)、これはお勧めしません。

テストに使用した例を次に示します。

  • いくつかのインターフェース:

    パブリック インターフェイス TestClassInterface {

    void testMethod();
    

    }

  • このインターフェイスを実装するいくつかのテスト クラス:

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor=Exception.class) @Component パブリック クラス TestClass は TestClassInterface を実装します {

    @Autowired
    private SpringDataFooDAO fooDao;
    
    public void testMethod() {
        try {
            Foo foo = fooDao.findOne(2L);
            System.out.println(TransactionSynchronizationManager.getCurrentTransactionName());
            System.out.println(TransactionSynchronizationManager.isActualTransactionActive());
            foo.setName("should be rolled back");
            new ExceptionThrower().doSomething("default string");
        } catch(Exception e) {
            updateSomeProperty(1L, "Changed name");
            throw new RuntimeException(e);
        }
    }
    
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor=Exception.class)
    private void updateSomeProperty(long id, String newFooName) {
    
        System.out.println("   ---   ");
        System.out.println(TransactionSynchronizationManager.getCurrentTransactionName());
        System.out.println(TransactionSynchronizationManager.isActualTransactionActive());
    
         // Update property of test object.
         Foo foo = fooDao.findOne(id);
         foo.setName(newFooName);    
    }
    

    }

  • 例外をスローするメソッドを持つ別のクラス:

    パブリック クラス ExceptionThrower {

    public void doSomething(Object obj) throws Exception {
        throw new Exception();  
     }
    

    }

catch ブロックから例外を再スローすることに注意してください (これは、上位クラスで処理する必要がないため、ランタイム例外として行います)。これは、外部トランザクションのロールバックを正しく行うために必要です。

于 2012-08-03T13:59:59.790 に答える
1

@Transactional の使用方法については、スプリング リファレンスを確認してください。Spring プロキシを使用する場合の @Transactional には、多くの **条件が適用されます。コードに適用する前に、それらを理解する必要があります。

プロキシ モード (デフォルト) では、プロキシ経由で着信する外部メソッド呼び出しのみがインターセプトされます。つまり、自己呼び出し、つまり、ターゲット オブジェクト内のメソッドがターゲット オブジェクトの別のメソッドを呼び出している場合、呼び出されたメソッドが @Transactional でマークされていても、実行時に実際のトランザクションは発生しません。

自己呼び出しもトランザクションでラップされることが予想される場合は、AspectJ モード (下の表のモード属性を参照) の使用を検討してください。この場合、そもそもプロキシはありません。代わりに、@Transactional を任意の種類のメソッドで実行時の動作に変えるために、ターゲット クラスが織り込まれます (つまり、そのバイト コードが変更されます)。

于 2012-08-03T14:01:32.893 に答える
0

noRollbackFor = RuntimeException.class または必要な他のクラスを指定してみてください。データベースを更新できることを願っています。すなわち @Transactional(noRollbackFor = RuntimeException.class)

于 2012-08-03T13:35:48.340 に答える
0

上記の配置は、新しいトランザクションを開始し、元のトランザクションとは異なる他のことを行うのに最適です。

私の場合に問題があったのは、他のトランザクションで自分で例外をスローしていたため、2 番目のトランザクションが再びロールバックされたことでした..

So The thing is beware off exception in the transaction because they ensure that the database state rolls back. It is for what they are meant for.   

ありがとう

于 2012-08-07T06:23:24.123 に答える
0

カスタム例外を作成し、それを使用してスローします。また、カスタム例外を定義する際に、クラス レベルのアノテーションとして @ApplicationException(rollback=false) を使用してください。

例えば

@ApplicationException(rollback=false)
public CustomException extends Exception{
于 2012-08-13T11:42:13.903 に答える