<div dir="ltr">小林 (koichik) 様<br><br>あきやまです。<br><br>ご回答ありがとうございます。<br><br>&gt; 対策としては、トランザクション境界の中で呼び出される<br>&gt; メソッド (上記のbar()に相当) には宣言的トランザクションを<br>&gt; 設定しないようにするか、特定の例外ではロールバックと<br>&gt; マークされないように設定する方法があります。<br>&gt; # 前者の方がよいかと思います。<br>&gt;<br>&gt; 後者については上記ドキュメントの「例外発生時の動作」に<br>&gt; 説明があります。<br>&gt; 実際に設定する場合はj2ee.diconをコピーして、<br>&gt; S2にバンドルされているejb3tx.diconを参考に<br>&gt; 一意制約違反発生時の例外でロールバックしないように<br>&gt; 設定してください。<br>前者に関してはPostgreSQLの場合、一意制約違反が発生した時点でトランザクションがアボートするらしく、<br>トランザクションを張りなおさないとDB操作ができない状態でした。<br>後者に関しては、以下の設定で試してみましたが、「既にロールバックとしてマーク」が出力され、期待通りの結果になりませんでした。<br><br>【ソース】<br>class xxxService {<br>  public void execute() {<br>    try {<br>      insertTx();<br>    } catch (...) {<br>      update()<br>    }<br>  }<br><br>  public void insertTx() {<br>  }<br><br>  public void update() {<br>  }<br>}<br><br>【j2ee.dicon】<br>&lt;component name=&quot;requiredTx&quot;<br>  class=&quot;org.seasar.extension.tx.RequiredInterceptor&quot;/&gt;<br>&lt;component name=&quot;requiresNewTx&quot;<br>  class=&quot;org.seasar.extension.tx.RequiresNewInterceptor&quot;/&gt;<br>&lt;component name=&quot;requiresNewEntityExistsCommitTx&quot;<br>  class=&quot;org.seasar.extension.tx.RequiresNewInterceptor&quot;&gt;<br>  &lt;initMethod name=&quot;addCommitRule&quot;&gt;<br>    &lt;arg&gt;@javax.persistence.EntityExistsException@class&lt;/arg&gt;<br>  &lt;/initMethod&gt;<br>&lt;/component&gt;<br>&lt;component name=&quot;mandatoryTx&quot;<br>  class=&quot;org.seasar.extension.tx.MandatoryInterceptor&quot;/&gt;<br>&lt;component name=&quot;notSupportedTx&quot;<br>  class=&quot;org.seasar.extension.tx.NotSupportedInterceptor&quot;/&gt;<br>&lt;component name=&quot;neverTx&quot;<br>  class=&quot;org.seasar.extension.tx.NeverInterceptor&quot;/&gt;<br><br><br>【customeizer.dicon】<br>&lt;component name=&quot;serviceCustomizer&quot;<br>  class=&quot;org.seasar.framework.container.customizer.CustomizerChain&quot;&gt;<br>  &lt;initMethod name=&quot;addCustomizer&quot;&gt;<br>    &lt;arg&gt;requiredTxCustomizer&lt;/arg&gt;<br>  &lt;/initMethod&gt;<br>  &lt;initMethod name=&quot;addCustomizer&quot;&gt;<br>    &lt;arg&gt;<br>      &lt;component class=&quot;org.seasar.framework.container.customizer.AspectCustomizer&quot;&gt;<br>        &lt;property name=&quot;interceptorName&quot;&gt;&quot;j2ee.requiresNewEntityExistsCommitTx&quot;&lt;/property&gt;<br>        &lt;property name=&quot;pointcut&quot;&gt;&quot;insertTx&quot;&lt;/property&gt;<br>      &lt;/component&gt;<br>    &lt;/arg&gt;<br>  &lt;/initMethod&gt;<br>&lt;/component&gt;<br><br>【アプリケーションログ】<br>org.seasar.framework.exception.SIllegalStateException: [ESSR0308]既にロールバックとしてマークされています<br>  at org.seasar.extension.jta.TransactionImpl.throwIllegalStateException(TransactionImpl.java:138)<br>  at org.seasar.extension.jta.TransactionImpl.assertActive(TransactionImpl.java:123)<br>  at org.seasar.extension.jta.TransactionImpl.enlistResource(TransactionImpl.java:452)<br>  at org.seasar.framework.util.TransactionUtil.enlistResource(TransactionUtil.java:64)<br>  at org.seasar.extension.dbcp.impl.ConnectionPoolImpl.checkOut(ConnectionPoolImpl.java:371)<br>  at org.seasar.extension.dbcp.impl.DataSourceImpl.getConnection(DataSourceImpl.java:59)<br>  at org.seasar.extension.jdbc.util.DataSourceUtil.getConnection(DataSourceUtil.java:51)<br>  at org.seasar.extension.jdbc.manager.JdbcManagerImpl.getJdbcContext(JdbcManagerImpl.java:381)<br>  at org.seasar.extension.jdbc.query.AbstractAutoUpdate.executeInternal(AbstractAutoUpdate.java:121)<br>  at org.seasar.extension.jdbc.query.AutoUpdateImpl.executeInternal(AutoUpdateImpl.java:145)<br>  at org.seasar.extension.jdbc.query.AbstractAutoUpdate.execute(AbstractAutoUpdate.java:90)<br>  at org.seasar.extension.jdbc.service.S2AbstractService.update(S2AbstractService.java:149)<br>  at jp.co.xxxx.dbaccess.service.xxxxService.insert(xxxxService.java:66)<br>  at jp.co.xxxx.dbaccess.service.xxxxService$$EnhancedByS2AOP$$7ae165.$$insert2$$invokeSuperMethod$$(xxxxService$$EnhancedByS2AOP$$7ae165.java)<br>  at jp.co.xxxx.dbaccess.service.xxxxService$$EnhancedByS2AOP$$7ae165$$MethodInvocation$$insert21.proceed(MethodInvocationClassGenerator.java)<br>  at org.seasar.extension.tx.DefaultTransactionCallback.execute(DefaultTransactionCallback.java:58)<br>  at org.seasar.extension.tx.adapter.JTATransactionManagerAdapter.required(JTATransactionManagerAdapter.java:65)<br>  at org.seasar.extension.tx.RequiredInterceptor.invoke(RequiredInterceptor.java:50)<br>  at jp.co.xxxx.dbaccess.service.xxxxService$$EnhancedByS2AOP$$7ae165$$MethodInvocation$$insert21.proceed(MethodInvocationClassGenerator.java)<br>  at jp.co.xxxx.dbaccess.service.xxxxService$$EnhancedByS2AOP$$7ae165.insert2(xxxxService$$EnhancedByS2AOP$$7ae165.java)<br>  at jp.co.xxxx.dbaccess.service.xxxxServiceTest.testUpdateDelFlg1(xxxxServiceTest.java:75)<br>  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)<br>  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)<br>  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)<br>  at java.lang.reflect.Method.invoke(Method.java:597)<br>  at junit.framework.TestCase.runTest(TestCase.java:168)<br>  at org.seasar.framework.unit.S2FrameworkTestCase.doRunTest(S2FrameworkTestCase.java:519)<br>  at org.seasar.extension.unit.S2TestCase.doRunTest(S2TestCase.java:103)<br>  at org.seasar.framework.unit.S2FrameworkTestCase.runBare(S2FrameworkTestCase.java:308)<br>  at junit.framework.TestResult$1.protect(TestResult.java:110)<br>  at junit.framework.TestResult.runProtected(TestResult.java:128)<br>  at junit.framework.TestResult.run(TestResult.java:113)<br>  at junit.framework.TestCase.run(TestCase.java:124)<br>  at junit.framework.TestSuite.runTest(TestSuite.java:243)<br>  at junit.framework.TestSuite.run(TestSuite.java:238)<br>  at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:83)<br>  at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)<br>  at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)<br>  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)<br>  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)<br>  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)<br>  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)<br>  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)<br>  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)<br>  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)<br>  at java.lang.reflect.Method.invoke(Method.java:597)<br>  at jp.co.dgic.eclipse.jdt.internal.junit.runner.DJUnitRunner.main(DJUnitRunner.java:49)<br><br>【s2.log】<br>2014-12-09 10:13:27,911 DEBUG TransactionImpl - トランザクションを開始しました。tx=[FormatId=4360, GlobalId=1418087601966/7, BranchId=]<br>2014-12-09 10:13:27,911 DEBUG TransactionImpl - トランザクションを開始しました。tx=[FormatId=4360, GlobalId=1418087601966/8, BranchId=]<br>2014-12-09 10:13:27,920 DEBUG ConnectionPoolImpl - 論理的なコネクションを取得しました。tx=[FormatId=4360, GlobalId=1418087601966/8, BranchId=]<br>2014-12-09 10:13:27,923 DEBUG AutoInsertImpl - insert into ・・・<br>2014-12-09 10:13:27,935 DEBUG TransactionImpl - トランザクションをコミットしました。tx=[FormatId=4360, GlobalId=1418087601966/8, BranchId=]<br>2014-12-09 10:13:27,935 DEBUG ConnectionWrapperImpl - 論理的なコネクションを閉じました。tx=[FormatId=4360, GlobalId=1418087601966/8, BranchId=]<br>2014-12-09 10:13:27,958 DEBUG TransactionImpl - トランザクションをロールバックしました。tx=[FormatId=4360, GlobalId=1418087601966/7, BranchId=]<br><br></div><div class="gmail_extra"><br><div class="gmail_quote">2014年12月9日 3:48 Koichi Kobayashi <span dir="ltr">&lt;<a href="mailto:koichik@improvement.jp" target="_blank">koichik@improvement.jp</a>&gt;</span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">小林 (koichik) です。<br>
<br>
おそらくですが、以下のドキュメントに書いてある<br>
ことかと思います。<br>
<br>
<a href="http://s2container.seasar.org/2.4/ja/tx.html" target="_blank">http://s2container.seasar.org/2.4/ja/tx.html</a><br>
<br>
「トランザクションを開始した場合でも引き継いだ場合でも、<br>
このインターセプタが適用されたメソッドが例外をスローした場合は、<br>
例外の種類に応じてトランザクションがロールバックされるように<br>
マークします。」<br>
<br>
つまり、<br>
<br>
public void foo() {<br>
  try {<br>
    bar();<br>
  } catch (...) {<br>
    ...<br>
  }<br>
}<br>
<br>
public void bar() {<br>
  throw ...;<br>
}<br>
<br>
foo()とbar()の両方に宣言的トランザクションが<br>
適用される場合、foo()でトランザクションを開始して<br>
bar()はそのトランザクションの中で呼び出されますが、<br>
bar()がスローする例外によってfoo()で開始した<br>
トランザクションは「ロールバックされるようにマーク」<br>
されます。<br>
そのため、foo()でその例外をキャッチしても、<br>
foo()からリターンする際にトランザクションは<br>
ロールバックされます。<br>
<br>
対策としては、トランザクション境界の中で呼び出される<br>
メソッド (上記のbar()に相当) には宣言的トランザクションを<br>
設定しないようにするか、特定の例外ではロールバックと<br>
マークされないように設定する方法があります。<br>
# 前者の方がよいかと思います。<br>
<br>
後者については上記ドキュメントの「例外発生時の動作」に<br>
説明があります。<br>
実際に設定する場合はj2ee.diconをコピーして、<br>
S2にバンドルされているejb3tx.diconを参考に<br>
一意制約違反発生時の例外でロールバックしないように<br>
設定してください。<br>
<div class="HOEnZb"><div class="h5"><br>
<br>
On Mon, 8 Dec 2014 19:02:32 +0900, あきやまじろう &lt;<a href="mailto:mayama0130@gmail.com">mayama0130@gmail.com</a>&gt; wrote:<br>
<br>
&gt; お世話になっております。あきやまと申します。<br>
&gt;<br>
&gt; 一意制約違反発生時の更新処理について教えてください。<br>
&gt;<br>
&gt; [動作環境]<br>
&gt; ・S2Container 2.4.45<br>
&gt; ・PostgreSQL 9.0.13<br>
&gt;<br>
&gt; 現在、以下の処理を実装しようとしていますが、<br>
&gt;<br>
&gt; 1.トランザクション開始(トランザクションA)<br>
&gt; 2.SELECT FOR UPDATEでAテーブルからレコードを取得<br>
&gt; 3.トランザクション開始(トランザクションB)<br>
&gt; 4.BテーブルのレコードをSELECT FOR UPDATEで取得<br>
&gt; →取得できなかった場合、レコードを登録<br>
&gt; →一意制約違反が発生した場合、レコードを更新<br>
&gt; 5.トランザクションBをコミット<br>
&gt; 6.CテーブルのレコードをSELECT FOR UPDATEで取得<br>
&gt; →取得できなかった場合、レコードを登録<br>
&gt; →一意制約違反が発生した場合、レコードを更新<br>
&gt; 7.トランザクションCをコミット<br>
&gt; 8.トランザクションAをコミット<br>
&gt;<br>
&gt; 項番4で一意制約違反が発生した場合にレコードを更新したいのですが、<br>
&gt; 「既にロールバックとしてマークされています」とログ出力され、更新できなくなり困っています。<br>
&gt; 項番1から8までをtry-catchして、項番1から再トライすれば、うまくいくのですが、<br>
&gt; 項番6でも一意制約違反の可能性があり、その場合try-catchをネストしないといけないので、できれば避けたいです。<br>
&gt; 何かいい対処方法があれば、ご教授の程よろしくお願いします。<br>
<br>
<br>
</div></div><span class="HOEnZb"><font color="#888888">--<br>
{<br>
  name: &quot;Koichi Kobayashi&quot;,<br>
  mail: &quot;<a href="mailto:koichik@improvement.jp">koichik@improvement.jp</a>&quot;,<br>
  blog: &quot;<a href="http://d.hatena.ne.jp/koichik/" target="_blank">http://d.hatena.ne.jp/koichik/</a>&quot;,<br>
  twitter: &quot;@koichik&quot;<br>
}<br>
<br>
_______________________________________________<br>
Seasar-user mailing list<br>
<a href="mailto:Seasar-user@ml.seasar.org">Seasar-user@ml.seasar.org</a><br>
<a href="https://ml.seasar.org/mailman/listinfo/seasar-user" target="_blank">https://ml.seasar.org/mailman/listinfo/seasar-user</a><br>
</font></span></blockquote></div><br></div>