Spring+Hibernate+Atomikos本地JTA的搭建

本文配项目源码,下载地址为:springhibernateatomikos.zip 

附官方提供Atomikos与tomcat的整合:http://www.atomikos.com/Documentation/Tomcat7Integration35 

事务管理器的选择

Spring重要的一个优点就是可以帮我们管理事务。Spring可以托管的事务分两类,

  1. 本地数据库事务;

  2. JTA事务。

本地事务只能管理一个数据源,不能跨数据源。如果想跨数据源,则必须使用JTA事务。

若想使用JTA服务,只有两种选择:

  1. J2EE容器。所有的J2EE容器都支持JTA规范。

  2. 独立于容器的第三方软件。比如JTOM, Atomikos, JbossTS等。独立JTS可以脱离容器运行。

因为tomcat不是一个完整的J2EE容器,不支持JTA,所以必须结合第三方软件实现JTA。

源码结构

Spring+Hibernate+Atomikos本地JTA的搭建_第1张图片

  1. App.java为程序的入口。里面提供了两个测试方法,一个运行本地事务,一个运行JTA事务。

  2. dao和hb与模型不多说。

  3. JtaService运行的是JTA事务,里面会对两个数据源进行操作。

  4. Service运行的是本地事务。

  5. applicationContext.xml定义了本地事务下的容器。

  6. applicationContext.xml定义了JTA事务下的容器,它依赖ds1.xml和ds2.xml。ds1定义了数据源A,ds2定义了数据源B。

  7. ds1.sql创建了数据库A,ds2.sql创建了数据库B。

开发过程

创建Maven项目

创建maven项目,然后编辑pom.xml,引入我们需要的资源:

Spring+Hibernate+Atomikos本地JTA的搭建_第2张图片

其中c3p0只是为本地事务服务的。如果用JTA事务,则必须配置XADatasourse。XADatasource由J2EE容器提供,或者向本项目,由Atomikos提供。

除了最后一个资源,其它资源都一目了然,很容易找到。最后一个资源是由com.automikos提供的:

    <dependency>
    	<groupId>com.atomikos</groupId>
    	<artifactId>transactions-hibernate3</artifactId>
    	<version>3.9.3</version>
    </dependency>

开发本地事务程序部分(略)

请直接查看源码。

编写JtaService

public class JtaService {
	private CustomerDao customerDaoA;
	private CustomerDao customerDaoB;
	
	@Transactional(propagation=Propagation.REQUIRED, readOnly=false, isolation=Isolation.READ_COMMITTED)
	public void createCustomer(Customer c, Customer c2) {
		this.customerDaoA.saveCustomer(c);
		this.customerDaoB.saveCustomer(c2);
	}
	
	// getters and setters
}

在JtaService中,使用来自两个数据源的customerDao。虽然两个数据源的数据库schema完全一样,但它们的确是跨数据库。customerDaoA和customerDaoB将在IOC容器中装配。

定义数据源A

<!-- ds1.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:s="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">

    <bean id="dataSource1" 
      class="com.atomikos.jdbc.AtomikosDataSourceBean" 
      init-method="init" destroy-method="close"> 
      <property name="uniqueResourceName"><value>dataSource1</value></property> 
      <property name="xaDataSourceClassName"> 
         <value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value> 
      </property> 
      <property name="xaProperties"> 
	        <props> 
	          <prop key="user">mysql</prop> 
	          <prop key="password">mysql</prop> 
	          <prop key="URL">jdbc:mysql://localhost:3306/test1</prop> 
	        </props> 
      </property>    
      <property name="poolSize" value="3"/> 
   </bean> 
   
   <bean id="sessionFactory1"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" destroy-method="destroy">
        <property name="dataSource" ref="dataSource1" />
        <property name="mappingResources">
            <list>
                <value>com/xpbug/hb/Customer.hbm.xml</value>
                <value>com/xpbug/hb/Order.hbm.xml</value>
                <value>com/xpbug/hb/Item.hbm.xml</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <value>
                hibernate.dialect=org.hibernate.dialect.MySQLDialect
                hibernate.show_sql=true
                hibernate.format_sql=false
            </value>
        </property>
    </bean>

    <bean id="customerDaoA" class="com.xpbug.dao.CustomerDao">
        <property name="sessionFactory" ref="sessionFactory1"/>
    </bean>    
</beans>

定义数据源B

略,与A类似,只是不同的名称和指向不同的DB。

定义TransactionManager

<!-- applicationContext-jta.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:s="http://www.springframework.org/schema/security"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd 
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

	<import resource="ds1.xml" />
	<import resource="ds2.xml" />

	<bean id="service" class="com.xpbug.service.JtaService">
		<property name="customerDaoA" ref="customerDaoA"></property>
		<property name="customerDaoB" ref="customerDaoB"></property>
	</bean>

	<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
		init-method="init" destroy-method="close">
		<property name="forceShutdown" value="false" />
	</bean>

	<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.J2eeUserTransaction">
		<property name="transactionTimeout" value="300" />
	</bean>

	<bean id="transactionManager"
		class="org.springframework.transaction.jta.JtaTransactionManager"
		depends-on="atomikosTransactionManager,atomikosUserTransaction">
		<property name="transactionManager" ref="atomikosTransactionManager" />
		<property name="userTransaction" ref="atomikosUserTransaction" />
		<property name="allowCustomIsolationLevels" value="true" />
	</bean>

	<tx:annotation-driven transaction-manager="transactionManager" />

</beans>

至此,装配完成。

Eclipse中本地运行

public static void main( String[] args ) {
    //new App().testLocalTransaction();
    new App().testJtaTransaction();
}
    
private void testJtaTransaction() {
    ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-jta.xml");
    JtaService s = (JtaService) context.getBean("service");
		
    Customer customer = new Customer();
    customer.setName("A");
    Order order = new Order();
    	order.setName("o1");
    	order.setCustomer(customer);
    	customer.getOrders().add(order);
    	Customer c1 = customer;
    	
    	customer = new Customer();
    	customer.setName("B");
    	order = new Order();
    	order.setName("o2");
    	order.setCustomer(customer);
    	customer.getOrders().add(order);
    	Customer c2 = customer;
    	
    s.createCustomer(c1, c2);
    context.close();
		
}

查看两个数据库A和B是否插入了数据。 

为了测试原子性,修改JtaService,人为破坏程序执行:

@Transactional(propagation=Propagation.REQUIRED, readOnly=false, isolation=Isolation.READ_COMMITTED)
	public void createCustomer(Customer c, Customer c2) {
		this.customerDaoA.saveCustomer(c);
		this.customerDaoB.saveCustomer(c2);
		throw new RuntimeException();
	}

让方法createCustomer最后抛出异常。运行App,查看两个数据库是否插入数据。

你可能感兴趣的:(spring,Hibernate,jta,atomikos)