そして、それはうまくいかないはずです。クラスの別のメソッドから 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"/>
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 ブロックから例外を再スローすることに注意してください (これは、上位クラスで処理する必要がないため、ランタイム例外として行います)。これは、外部トランザクションのロールバックを正しく行うために必要です。