web-dev-qa-db-ja.com

weblogicと同じように、SpringBootアプリケーションでタイムアウト後のトランザクションをロールバックする方法

したがって、私のweblogicアプリケーションでは、jtaWeblogicTransactionManagerを使用しています。アノテーション@Transactional(timeout = 60)でオーバーライドできるデフォルトのタイムアウトがいくつかあります。正しくタイムアウトするdbからデータを読み取るための無限ループを作成しました。

29 Apr 2018 20:44:55,458 WARN  [[ACTIVE] ExecuteThread: '9' for queue: 'weblogic.kernel.Default (self-tuning)'] org.springframework.jdbc.support.SQLErrorCodesFactory : Error while extracting database name - falli
ng back to empty error codes
org.springframework.jdbc.support.MetaDataAccessException: Error while extracting DatabaseMetaData; nested exception is Java.sql.SQLException: Unexpected exception while enlisting XAConnection Java.sql.SQLExceptio
n: Transaction rolled back: Transaction timed out after 240 seconds 
BEA1-2C705D7476A3E21D0AB1
        at weblogic.jdbc.jta.DataSource.enlist(DataSource.Java:1760)
        at weblogic.jdbc.jta.DataSource.refreshXAConnAndEnlist(DataSource.Java:1645)
        at weblogic.jdbc.wrapper.JTAConnection.getXAConn(JTAConnection.Java:232)
        at weblogic.jdbc.wrapper.JTAConnection.checkConnection(JTAConnection.Java:94)
        at weblogic.jdbc.wrapper.JTAConnection.checkConnection(JTAConnection.Java:77)
        at weblogic.jdbc.wrapper.Connection.preInvocationHandler(Connection.Java:107)
        at weblogic.jdbc.wrapper.Connection.getMetaData(Connection.Java:560)
        at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.Java:331)
        at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.Java:366)
        at org.springframework.jdbc.support.SQLErrorCodesFactory.getErrorCodes(SQLErrorCodesFactory.Java:212)
        at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.setDataSource(SQLErrorCodeSQLExceptionTranslator.Java:134)
        at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.<init>(SQLErrorCodeSQLExceptionTranslator.Java:97)
        at org.springframework.jdbc.support.JdbcAccessor.getExceptionTranslator(JdbcAccessor.Java:99)
        at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.Java:655)
        at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.Java:690)

今、私は私の春のブートアプリケーションで同じ動作をしたいので、これを試しました:

@EnableTransactionManagement
.
.
.

@Bean(name = "ds1")
@ConfigurationProperties(prefix = "datasource.ds1")
public DataSource logDataSource() {
    AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
    return ds;
}

@Bean(name = "ds2")
@ConfigurationProperties(prefix = "datasource.ds2")
public DataSource refDataSource() {
    AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
    return ds;
}

tm:

@Bean(name = "userTransaction")
public UserTransaction userTransaction() throws Throwable {
    UserTransactionImp userTransactionImp = new UserTransactionImp();
    userTransactionImp.setTransactionTimeout(120);
    return userTransactionImp;
}

@Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close")
public TransactionManager atomikosTransactionManager() throws Throwable {
    UserTransactionManager userTransactionManager = new UserTransactionManager();
    userTransactionManager.setForceShutdown(false);
    userTransactionManager.setTransactionTimeout(120);
    return userTransactionManager;
}

@Bean(name = "transactionManager")
@DependsOn({ "userTransaction", "atomikosTransactionManager" })
public JtaTransactionManager transactionManager() throws Throwable {
    UserTransaction userTransaction = userTransaction();
    TransactionManager atomikosTransactionManager = atomikosTransactionManager();
    return new JtaTransactionManager(userTransaction, atomikosTransactionManager);
}

およびapplication.properties:

datasource.ref.xa-data-source-class-name=Oracle.jdbc.xa.client.OracleXADataSource
datasource.ref.unique-resource-name=ref
datasource.ref.xa-properties.URL=jdbc:Oracle:thin:@...
datasource.ref.xa-properties.user=...
#datasource.ref.xa-properties.databaseName=...
datasource.ref.password=301d24ae7d0d69614734a499df85f1e2
datasource.ref.test-query=SELECT 1 FROM DUAL
datasource.ref.max-pool-size=5

datasource.log.xa-data-source-class-name=Oracle.jdbc.xa.client.OracleXADataSource
datasource.log.unique-resource-name=log
datasource.log.xa-properties.URL=jdbc:Oracle:thin:@...
datasource.log.xa-properties.user=...
#datasource.log.xa-properties.databaseName=...
datasource.log.password=e58605c2a0b840b7c6d5b20b3692c5db
datasource.log.test-query=SELECT 1 FROM DUAL
datasource.log.max-pool-size=5

spring.jta.atomikos.properties.log-base-dir=target/transaction-logs/
spring.jta.enabled=true
spring.jta.atomikos.properties.service=com.atomikos.icatch.standalone.UserTransactionServiceFactory
spring.jta.atomikos.properties.max-timeout=600000
spring.jta.atomikos.properties.default-jta-timeout=10000
spring.transaction.default-timeout=900

しかし、成功しませんでした。無限ループが終了することはありません(約15分待ってから、アプリを停止します)。ロールバックが表示されたのは、Thread.sleepを試したときだけで、スリープ後にこのトランザクションはロールバックでタイムアウトしましたが、これは私が望んでいることではありません。それで、私のweblogicアプリケーションと同じように、タイムアウト後にプロセスを中断する(注釈でタイムアウトを使用するか、デフォルトを使用する)方法はありますか?

[〜#〜]更新[〜#〜]

私はそれを次のようにテストしました:

public class MyService {

public void customMethod(){

customDao.readSomething();

}

}

public class CustomDao {

@Transactional(timeout = 120)
public void readSomething()

while(true){
 //read data from db. app on weblogic throw timeout, spring boot app in docker did  nothing and after 15 I give it up and kill it
}
}

}

PDATE2

アトミコスデバッグをオンにすると、初期化中に警告が表示され、アトミコスタイマーがいくつか表示されます。

2018-05-03 14:00:54.833 [main] WARN  c.a.r.xa.XaResourceRecoveryManager - Error while retrieving xids from resource - will retry later...
javax.transaction.xa.XAException: null
    at Oracle.jdbc.xa.OracleXAResource.recover(OracleXAResource.Java:730)
    at com.atomikos.datasource.xa.RecoveryScan.recoverXids(RecoveryScan.Java:32)
    at com.atomikos.recovery.xa.XaResourceRecoveryManager.retrievePreparedXidsFromXaResource(XaResourceRecoveryManager.Java:158)
    at com.atomikos.recovery.xa.XaResourceRecoveryManager.recover(XaResourceRecoveryManager.Java:67)
    at com.atomikos.datasource.xa.XATransactionalResource.recover(XATransactionalResource.Java:449)
    at com.atomikos.datasource.xa.XATransactionalResource.setRecoveryService(XATransactionalResource.Java:416)
    at com.atomikos.icatch.config.Configuration.notifyAfterInit(Configuration.Java:466)
    at com.atomikos.icatch.config.Configuration.init(Configuration.Java:450)
    at com.atomikos.icatch.config.UserTransactionServiceImp.initialize(UserTransactionServiceImp.Java:105)
    at com.atomikos.icatch.config.UserTransactionServiceImp.init(UserTransactionServiceImp.Java:219)
    at com.atomikos.icatch.jta.UserTransactionImp.checkSetup(UserTransactionImp.Java:59)
    at com.atomikos.icatch.jta.UserTransactionImp.setTransactionTimeout(UserTransactionImp.Java:127)

多分これが理由です。どうすればこれを修正できますか? Oracle12とojdbc8ドライバーを使用しています

更新

uPDATE2を修正してdbにユーザー権限を付与した後、ログ警告で確認できます。

2018-05-03 15:16:30.207 [Atomikos:4] WARN  c.a.icatch.imp.ActiveStateHandler - Transaction 127.0.1.1.tm152535336001600001 has timed out and will rollback.

問題は、このタイムアウト後もアプリがdbからデータを読み取っているということです。なぜロールバックされないのですか?

更新4

そのため、タイムアウトが発生するとActiveStateHandlerに次のコードがあります。

...

        setState ( TxState.ACTIVE );
...

AtomikosConnectionProxyはこの方法でタイムアウトをチェックしています

if ( ct.getState().equals(TxState.ACTIVE) ) ct.registerSynchronization(new JdbcRequeueSynchronization( this , ct ));
else AtomikosSQLException.throwAtomikosSQLException("The transaction has timed out - try increasing the timeout if needed");

では、なぜタイムアウトがAtomikosConnectionProxyで例外を引き起こさない状態に設定されているのでしょうか。

更新5

だから私はそのプロパティを見つけました

com.atomikos.icatch.threaded_2pc

私の問題を解決し、今では私が望む方法でロールバックを開始します。しかし、シングルスレッドで実行する必要があるいくつかのタスクでテストしているため、これをtrueに設定する必要がある理由がまだわかりません

11
hudi

セットする com.atomikos.icatch.threaded_2pc=true in jta.properties私の問題を修正しました。 Idkこのデフォルト値がWebアプリケーションでfalseに変更された理由。

 * @param single_threaded_2pc (!com.atomikos.icatch.threaded_2pc)
 *           If true then commit is done in the same thread as the one that
 *            started the tx.
3
hudi

XAトランザクション 非常に複雑であり、それらを使用する非常に正当な理由が必要です(つまり、XAの必要性を排除するビジネスプロセスを追加することは文字通り不可能です)。野生でトラブル...

そうは言っても、私の推測では、XAフェーズ間のタイムアウトの不一致に関するものだと思います。

XAには、2つのタイムアウトがあります。投票フェーズと呼ばれる第1フェーズのタイムアウト(通常は@Transactionalアノテーションによって設定されますが、これはJTAプロバイダーによって異なります)と、第2フェーズのタイムアウトです。コミットフェーズ。通常ははるかに長くなります。これは、トランザクションマネージャーがすべての関係者からコミットの準備ができているという合意をすでに取得しているため、一時的なネットワーク障害などに対してより大きな余裕があります。

私の推測では、WebLogic JTAは、アトミコスがマルチスレッドackを使用するように変更されるまで、参加者からの第2フェーズ通知の処理方法がアトミコスとは異なる動作をしているだけだと思います。

アプリケーションがあなたとデータベースだけである場合は、XA TransactionManagerがなくてもおそらく逃げることができます。これは、タイムアウトに対して希望どおりに動作すると思います。

幸運を!

0
stringy05