Я пытаюсь протестировать распределенные транзакции / транзакции XA.
Я использую mySql, Oracle, Atomikos и spring
Сервер приложений не используется - поэтому, пожалуйста, не указывайте мне на решения для сервера приложений.
В транзакции - сначала пытаюсь обновить таблицу Oracle
Затем в той же транзакции пытаюсь вставить в MySql
Я гарантирую, что вставка завершится неудачно из-за ограничения уникальности таблицы.
В идеале, поскольку mysql был неудачным - обновление Oracle также должно быть выполнено откатом - но этого, похоже, не происходит - обновление таблицы Oracle происходит на основе sysdate.
Итак, вот полный код:
spring configfile:
<bean id="userTransactionService" class="com.atomikos.icatch.config.UserTransactionServiceImp"
init-method="init" destroy-method="shutdownForce">
<constructor-arg>
<props>
<prop key="com.atomikos.icatch.service">
com.atomikos.icatch.standalone.UserTransactionServiceFactory
</prop>
<prop key="com.atomikos.icatch.tm_unique_name">myname</prop>
<prop key="com.atomikos.icatch.log_base_name">myLogName</prop>
<prop key="com.atomikos.icatch.log_base_dir">xyz/atomikos</prop>
<prop key="com.atomikos.icatch.checkpoint_interval">100</prop>
<prop key="com.atomikos.icatch.console_file_count">2</prop>
<prop key="com.atomikos.icatch.max_timeout">300000</prop>
<prop key="com.atomikos.icatch.max_actives">128</prop>
</props>
</constructor-arg>
</bean>
<bean id="AtomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close" depends-on="userTransactionService">
<property name="startupTransactionService" value="false" />
<property name="forceShutdown" value="false" />
</bean>
<bean id="AtomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp"
depends-on="userTransactionService">
<property name="transactionTimeout" value="300" />
</bean>
<bean id="jtaTxManager"
class="org.springframework.transaction.jta.JtaTransactionManager"
depends-on="userTransactionService">
<property name="transactionManager" ref="AtomikosTransactionManager" />
<property name="userTransaction" ref="AtomikosUserTransaction" />
</bean>
<bean id="myTxTest" class="com.runner.MyTxTester">
<property name="oraUpdater" ref="myOraUpdater" />
<property name="mySqlInserter" ref="mySqlInserter" />
<property name="txManager" ref="jtaTxManager" />
</bean>
<bean id="mySqlInserter" class="com.xyz.dao.MySqlInserter">
<property name="sql"
value="insert into person (name,country) values ('abc','USA');" />
<property name="dataSource" ref="MySqldataSource" />
</bean>
<bean id="myOraUpdater" class="com.xyz.dao.OraUpdater">
<property name="sql"
value="UPDATE PurchaseOrders SET LAST_UPDATE=SYSDATE" />
<property name="dataSource" ref="OraDataSource" />
</bean>
<bean id="OraDataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close" lazy-init="true">
<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" />
<property name="username" value="TEST1" />
<property name="password" value="TEST11" />
<property name="driverClassName" value="oracle.jdbc.xa.client.OracleXADataSource" />
</bean>
<bean id="MySqldataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close" lazy-init="true">
<property name="url" value="jdbc:mysql://localhost/test2" />
<property name="username" value="test2" />
<property name="password" value="test2" />
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
</bean>
Вот как я запускаю все:
public static void main(String[] args) {
try{
ApplicationContext context = new ClassPathXmlApplicationContext("instance-spring.xml");
MyTxTester tester = (MyTxTester) context.getBean("myTxTest");
tester.wrapperCall();
}catch (Exception e){
e.printStackTrace();
}
}
Класс, который вызывает вещи:
public class MyTxTester {
private final SQLErrorCodeSQLExceptionTranslator exceptionTranslator = new SQLErrorCodeSQLExceptionTranslator();
private PlatformTransactionManager txManager;
private DBUpdater<SqlParameterSource> oraUpdater;
private DBUpdater<SqlParameterSource> mySqlInserter;
public void wrapperCall(){
TransactionTemplate txTemplate = new TransactionTemplate(txManager);
txTemplate.execute(new TransactionCallback<Object>() {
public Object doInTransaction(TransactionStatus transactionStatus) {
try {
//do oracle update
doOraUpdate();
//do mysql insert
doMySqlInsert();
} catch (Exception sqle) {
throw exceptionTranslator.translate("SQLException ","abc", new SQLException());
}
return null;
}
});
}
public void doOraUpdate(){
System.out.println(" first going for Oracle update ");
getOraUpdater().update();
}
public void doMySqlInsert(){
System.out.println(" second going for mySql insert ");
getMySqlInserter().insert();
}
Класс Дао -
public class OraUpdater<E extends SqlParameterSource> {
/** The data source. */
private DataSource dataSource;
/** The jdbc template. */
private NamedParameterJdbcTemplate jdbcTemplate;
/** The sql. */
private String sql;
public Object update() {
SqlParameterSource paramSource = null;
getJdbcTemplate().update(getSql(), paramSource);
return null;
}
MySqlDao:
public class MySqlInserter<E extends SqlParameterSource> {
/** The data source. */
private DataSource dataSource;
/** The jdbc template. */
private NamedParameterJdbcTemplate jdbcTemplate;
/** The sql. */
private String sql;
public Object insert() {
SqlParameterSource paramSource = null;
getJdbcTemplate().update(getSql(), paramSource);
return null;
}
Так не знаете, чего мне не хватает, чтобы обеспечить атомарность?