Как откатить транзакцию после тайм-аута при весенней загрузке приложения так же, как на weblogic - PullRequest
0 голосов
/ 30 апреля 2018

Итак, в моем приложении для weblogic мы используем jtaWeblogicTransactionManager. Существует некоторое время ожидания по умолчанию, которое можно переопределить в аннотации @Transactional(timeout = 60). Я создал некоторый бесконечный цикл для чтения данных из БД, который корректно истекает:

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;
}

тм:

@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?

UPDATE

Я проверил это так:

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
}
}

}

UPDATE2

Когда я включаю отладку atomikos, я вижу, что во время инициализации появляется предупреждение и таймер atomikos:

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)

может быть, в этом причина. Как я могу это исправить? Я использую oracle 12 с драйвером ojdbc8

ОБНОВЛЕНИЕ 3

после исправления UPDATE2 для предоставления пользователю прав доступа к БД. Я вижу в журнале предупреждение:

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.

Проблема в том, что приложение все еще читает данные из БД после этого времени ожидания. Почему не откатывается?

ОБНОВЛЕНИЕ 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, потому что сейчас я тестирую его на какой-то задаче, которая должна выполняться в одном потоке

Ответы [ 2 ]

0 голосов
/ 09 мая 2018

XA-транзакции ужасно сложны, и вы действительно хотите иметь очень веские основания для их использования (т. Е. Буквально невозможно добавить какой-либо бизнес-процесс, который устраняет необходимость в XA), потому что вы собираетесь попасть в беду в дикой природе ...

Тем не менее, я предполагаю, что речь идет о расхождениях по таймауту между фазами XA.

В XA есть 2 тайм-аута - тайм-аут для 1-й фазы, известный как фаза голосования (которая обычно устанавливается аннотацией @Transactional, но зависит от провайдера JTA), и другой тайм-аут для 2-й фазы Он называется фазой фиксации, которая, как правило, намного дольше, потому что Менеджер транзакций уже получил согласие всех сторон на то, что фиксация готова к выполнению, и, следовательно, обеспечивает большую свободу действий для таких вещей, как временные сбои в сети и так далее.

Я предполагаю, что JTA WebLogic просто ведет себя иначе, чем Atomikos, с тем, как он обрабатывает уведомления 2-й фазы обратно от участников, пока atomikos не будет изменен для использования многопоточного ack.

Если ваше приложение - это только вы и база данных, то вы, вероятно, можете обойтись без XA Transaction Manager. Я ожидаю, что это будет вести себя так, как вы хотите для тайм-аутов.

Удачи!

0 голосов
/ 04 мая 2018

set com.atomikos.icatch.threaded_2pc=true in jta.properties исправил мою проблему. Определите, почему это значение по умолчанию было изменено на 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.
...