我正在创建一个示例应用程序来测试两阶段提交(2PC).我已经从互联网上获取了此处使用的代码位.我正在将Spring,Hibernate和Atomikos与MySQL用作后端.我正在使用两个数据库,故意对第二个数据库进行调用无法检查是否对第一个数据库调用进行了回滚.不幸的是,它似乎不起作用.有人可以指出一些示例代码的链接吗?
以下是我的配置:
Hibernate会话工厂:
<bean id="sessionFactory1" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource1"/>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.connection.isolation">3</prop>
<prop key="hibernate.current_session_context_class">jta</prop>
<prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</prop>
<prop key="hibernate.transaction.manager_lookup_class">com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup</prop>
<prop key="hibernate.connection.release_mode">on_close</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>/hibernate/Stock.hbm.xml</value>
</list>
</property>
</bean>
<bean id="sessionFactory2" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource2"/>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.connection.isolation">3</prop>
<prop key="hibernate.current_session_context_class">jta</prop>
<prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</prop>
<prop key="hibernate.transaction.manager_lookup_class">com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup</prop>
<prop key="hibernate.connection.release_mode">on_close</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>/hibernate/Stock1.hbm.xml</value>
</list>
</property>
</bean>
dataSource配置:
<bean id="dataSource1" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
<!-- set an arbitrary but unique name for the datasource -->
<property name="uniqueResourceName"><value>XADBMS1</value></property>
<!-- set the underlying driver class to use, in this example case we use MySql -->
<property name="xaDataSourceClassName">
<value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>
</property>
<property name="xaProperties">
<!-- set the driver-specific XADataSource properties (check your driver docs for more info) -->
<props>
<prop key="user">${jdbc.username}</prop>
<prop key="password">${jdbc.password}</prop>
<prop key="URL" >${jdbc.url1}</prop>
</props>
</property>
<!-- how many connections in the pool? -->
<property name="poolSize" value="3"/>
</bean>
<bean id="dataSource2" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
<!-- set an arbitrary but unique name for the datasource -->
<property name="uniqueResourceName"><value>XADBMS2</value></property>
<!-- set the underlying driver class to use, in this example case we use MySql -->
<property name="xaDataSourceClassName">
<value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>
</property>
<property name="xaProperties">
<!-- set the driver-specific XADataSource properties (check your driver docs for more info) -->
<props>
<prop key="user">${jdbc.username}</prop>
<prop key="password">${jdbc.password}</prop>
<prop key="URL" >${jdbc.url2}</prop>
</props>
</property>
<!-- how many connections in the pool? -->
<property name="poolSize" value="3"/>
</bean>
Spring JTA配置:
<bean id="AtomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close">
<!-- when close is called, should we force transactions to terminate or not? -->
<property name="forceShutdown" value="false" />
</bean>
<!--Also use Atomikos UserTransactionImp, needed to configure Spring -->
<bean id="AtomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
<property name="transactionTimeout" value="300" />
</bean>
<!--Configure the Spring framework to use JTA transactions from Atomikos -->
<bean id="JtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="AtomikosTransactionManager" />
<property name="userTransaction" ref="AtomikosUserTransaction" />
</bean>
我有两个DAOImpl,将上面定义的两个sessionFactory注入其中.以下是来自Java代码的调用:
public static void main( String[] args )
{
ApplicationContext appContext =
new ClassPathXmlApplicationContext("spring/config/appContext.xml");
StockBo stockBo = (StockBo)appContext.getBean("stockBo1");
StockBo stockBo2 = (StockBo)appContext.getBean("stockBo2");
/** insert **/
Stock stock = new Stock();
stock.setStockCode("7668");
stock.setStockName("HAIO");
stockBo.save(stock);
Stock stock1 = new Stock();
//stock1.setStockCode("1668"); **Commented to fail the second db insert**
stock1.setStockName("AAIO");
stockBo2.save(stock1);
}
任何指针都会有很大帮助.
谢谢
解决方法:
若要获得您期望的行为,您需要在同一事务内执行DAO调用,例如,如下所示:
final StockBo stockBo = (StockBo)appContext.getBean("stockBo1");
final StockBo stockBo2 = (StockBo)appContext.getBean("stockBo2");
TransactionTemplate tx = new TransactionTemplate(appContext.getBean(PlatformTransactionManager.class);
tx.execute(new TransactionCallback<Void>() {
public Void doInTransaction(TransactionStatus ts) {
/** insert **/
Stock stock = new Stock();
stock.setStockCode("7668");
stock.setStockName("HAIO");
stockBo.save(stock);
Stock stock1 = new Stock();
//stock1.setStockCode("1668"); **Commented to fail the second db insert**
stock1.setStockName("AAIO");
stockBo2.save(stock1);
return null;
}
});
另外,由于您使用Spring配置了Hibernate,因此我认为您不需要以下几行:
<prop key="hibernate.current_session_context_class">jta</prop>
<prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</prop>
<prop key="hibernate.transaction.manager_lookup_class">com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup</prop>
<prop key="hibernate.connection.release_mode">on_close</prop>
也可以看看: