`

JPA & XA

    博客分类:
  • JEE
阅读更多

After I wrote a blog about Spring & JPA settings: http://jellyfish.iteye.com/admin/blogs/899281, a friend asked me a question about XA on JPA.

 

Last time I did XA was the year 2002, so I figured maybe it's time to revisit this topic to see how things have changed since then. Well, a lot, frankly.

 

I did XA across two data sources, db2 and sybase; and across a data source and a JMS queue. I am using Spring 3 now, the first thing that I noticed is that for some unknown reason, Spring 3 drop the JOTM support (Spring 2.5 had it). Does anyone know the reason behind it?

 

So I am going to use Atomikos's libs for XA. I started from the above blog to see how much I need to change in order to get XA working.

 

First, the persistence file needs a little change (marked in red):

 

<?xml version="1.0" encoding="UTF-8" ?>

<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
	version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">

    <persistence-unit name="myPersistenceUnit" transaction-type="JTA">
        <mapping-file>my/test/dao/jpa/hibernate/book.jpa.hibernate.xml</mapping-file>
    </persistence-unit>
</persistence>

 I rename this file to persistence.jta.xml, since we need to reference this file later. Next, we need to change the Spring xml file, since the change is pretty dramatic, I just paste the entire file and then explain the beans one by one later:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-3.0.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <bean id="bookService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="transactionManager" ref="springTransactionManager"/>
        <property name="target" ref="bookServiceTarget"/>
        <property name="transactionAttributes">
            <props>
                <prop key="*">PROPAGATION_REQUIRED, -Exception</prop>
            </props>
        </property>
    </bean>

    <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>
            </props>
        </constructor-arg>
    </bean>

    <bean id="springTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
        <property name="transactionManager">
            <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
                  init-method="init" destroy-method="close" depends-on="userTransactionService">
                <property name="forceShutdown" value="false"/>
                <property name="startupTransactionService" value="false"/>
            </bean>
        </property>
        <property name="userTransaction">
            <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp" depends-on="userTransactionService">
                <property name="transactionTimeout" value="5"/>
            </bean>
        </property>
        <property name="allowCustomIsolationLevels" value="true"/>
    </bean>

    <bean id="bookServiceTarget" class="my.test.dao.jpa.hibernate.BookService">
        <property name="dao1" ref="bookDao1"/>
        <property name="dao2" ref="bookDao2"/>
    </bean>
    
    <bean id="bookDao1" class="my.test.dao.jpa.hibernate.BookDaoJpaHibernateJtaImpl">
        <property name="entityManager">
            <bean class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
                <property name="entityManagerFactory" ref="myEmf1"/>
            </bean>
        </property>
    </bean>

    <bean id="bookDao2" class="my.test.dao.jpa.hibernate.BookDaoJpaHibernateJtaImpl">
        <property name="entityManager">
            <bean class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
                <property name="entityManagerFactory" ref="myEmf2"/>
            </bean>
        </property>
    </bean>

    <bean id="myEmf1" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="myPersistenceUnit"/>
        <property name="dataSource" ref="mydataSource1"/>
        <property name="persistenceXmlLocation" value="classpath:my/test/dao/jpa/hibernate/persistence.jta.xml"/>
        <property name="loadTimeWeaver">
            <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
        </property>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <!-- <property name="showSql" value="true"/> -->
                <property name="generateDdl" value="false"/>
                <property name="database" value="ORACLE"/>
                <property name="databasePlatform" value="org.hibernate.dialect.OracleDialect"/>
            </bean>
        </property>
        <property name="jpaProperties">
            <map>
                <entry key="hibernate.transaction.manager_lookup_class"
                       value="com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup"/>
            </map>
        </property>
    </bean>

    <bean id="myEmf2" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="myPersistenceUnit"/>
        <property name="dataSource" ref="mydataSource2"/>
        <property name="persistenceXmlLocation" value="classpath:my/test/dao/jpa/hibernate/persistence.jta.xml"/>
        <property name="loadTimeWeaver">
            <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
        </property>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <!-- <property name="showSql" value="true"/> -->
                <property name="generateDdl" value="false"/>
                <property name="database" value="ORACLE"/>
                <property name="databasePlatform" value="org.hibernate.dialect.OracleDialect"/>
            </bean>
        </property>
        <property name="jpaProperties">
            <map>
                <entry key="hibernate.transaction.manager_lookup_class"
                       value="com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup"/>
            </map>
        </property>       
    </bean>

    <bean id="mydataSource1" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
        <property name="xaDataSourceClassName" value="oracle.jdbc.xa.client.OracleXADataSource"/>
        <property name="uniqueResourceName" value="mydataSource1"/>
        <property name="poolSize" value="1"/>
        <property name="xaProperties">
            <props>
                <prop key="URL">jdbc:oracle:thin:@***</prop>
                <prop key="user">***</prop>
                <prop key="password">***</prop>
            </props>
		</property>
    </bean>

    <bean id="mydataSource2" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
        <property name="xaDataSourceClassName" value="oracle.jdbc.xa.client.OracleXADataSource"/>
        <property name="uniqueResourceName" value="mydataSource2"/>
        <property name="poolSize" value="1"/>
        <property name="xaProperties">
            <props>
                <prop key="URL">jdbc:oracle:thin:@***</prop>
                <prop key="user">***</prop>
                <prop key="password">***</prop>
            </props>
		</property>
    </bean>    
</beans>

 Let's go through this from bottom up. The last two beans are (different) data sources (I am using Oracle), make sure you use XA jdbc drivers. We want to test out the transaction management across two different databases (could be oracle/sybase/db2/sqlserver).

 

The next two beans are entity manager factor (emf). We first changed the persistence.xml new path, then add a "jpaProperties" entry according to Atomikos's document:

http://www.atomikos.com/Documentation/SpringIntegration

http://www.atomikos.com/Documentation/HibernateIntegration

 

Now the DAO class is little bit problematic since the emf was injected through @PersistenceContext. Let's remove this annotation and create a setter, like this:

public class BookDaoJpaHibernateJtaImpl  implements BookDao
{
    private EntityManager em;

    public void setEntityManager(EntityManager em)
    {
        this.em = em;
    }

    // other methods are the same
}

 So the next two DAO beans (bookDao1 and bookDao2) use this class. The emf fields are injected separately.

 

Next, we create a new class that uses the above two DAO classes:

package my.test.dao.jpa.hibernate;

import my.test.Book;
import my.test.BookDao;

public class BookService
{
    private BookDao dao1;
    private BookDao dao2;

    public void save(Book book)
    {

        dao2.save(book);
        dao1.save(book);
    }

    public void setDao2(BookDao dao2)
    {
        this.dao2 = dao2;
    }

    public void setDao1(BookDao dao1)
    {
        this.dao1 = dao1;
    }
}

 and we have the corresponding bean bookServiceTarget.

 

The next two beans are Atomikos related, together they define the transaction manager. Please check Atomikos document.

 

Finally, the first bean bookService stitch the bookServiceTarget and the transaction manager together.

 

During testing, I created two same tables in each database, add an unique index for book_id on the table in the second database. Then insert a simple book object through book service. The first run should be fine since both database tables are empty. The second run should fail because the same id

was tried to be inserted into the table in the second database. After the second run, both tables should have count 1 on rows (i.e., the second run got rolled back).

分享到:
评论

相关推荐

    03_JPA详解_搭建JPA开发环境和全局事务介绍.zip

    **JPA(Java Persistence API)**是Java平台上的一个标准,用于管理关系数据库中的数据,它简化了ORM(对象关系映射)的过程。本资料主要针对JPA的使用进行详细讲解,包括如何搭建JPA开发环境以及全局事务的介绍。 ...

    Springboot+Atomikos+Jpa+Mysql实现JTA分布式事务

    本文将详细讲解如何利用Spring Boot、Atomikos、JPA(Java Persistence API)以及MySQL来实现JTA(Java Transaction API)分布式事务。 首先,Spring Boot是一个轻量级的框架,它简化了基于Spring的应用程序开发...

    03_传智播客JPA详解_搭建JPA开发环境和全局事务介绍

    3. **JTA事务协调**:在分布式环境中,JTA允许应用程序在不同的数据源之间协调事务,例如使用UserTransaction接口来启动和结束事务,配合XAResource实现跨数据库的事务一致性。 了解以上基础后,你可以观看"03_传智...

    spring jpa

    Spring JTA 提供了与 JNDI 配合的事务管理,以及 Atomikos、Bitronix 等第三方事务管理器的集成,以支持 XA 事务。 总的来说,Spring JPA 是一个强大的 ORM 解决方案,它结合了 Spring 的便利性和 JPA 的规范,为...

    springboot-集成达梦数据库-源代码

    jpa-hibernate-dm: 数据库为{国产达梦数据库},持久层技术为jpa-hibernate mybatis-dm: 数据库为{国产达梦数据库},持久层技术为mybatis mybatis-plus-dm: 数据库为{国产达梦数据库},持久层技术为mybatis-plus 补充...

    spring-jta-narayana:JTA,JPA,Hibernate和Narayana的Spring项目

    将MySQL驱动程序更改为XA实施支持。 添加到applicationContext.xml transactionManager参考并注释旧的transactionManager设置。 在tx:annotation-driven的applicationContext.xml中指示事务管理器。 另外包含:...

    jboss7.1.1+ejb3.0+MySQL数据源配置

    &lt;xa-datasource-class&gt;com.mysql.jdbc.Driver&lt;/xa-datasource-class&gt; ... ``` 配置完成后,可以通过JNDI名称`java:jboss/datasources/MySqlDS`在EJB中获取数据源并进行数据库操作。 项目源码的导入则涉及到...

    jta.jar包;jta.jar包

    6. **JTA与JDBC/Java Persistence API (JPA)**: 在JDBC连接上启用JTA事务,需要使用`javax.sql.DataSource.getConnection(UserTransaction, ConnectionProperties)`方法,或者在JPA中通过`@Transactional`注解声明...

    ejb3.0 分布式事务

    `ejb_jpa01client`可能包含了调用EJB服务并参与分布式事务的代码,而`ejb_jpa01`可能包含了EJB组件和相关的持久化配置。通过分析这些文件,我们可以深入了解ejb3.0如何在实际应用中处理分布式事务。 在实际开发中,...

    mysql 不能插入中文问题

    ### MySQL 不能插入中文问题详解 #### 问题现象 在使用 MySQL 5.5 版本进行数据操作时,部分用户遇到了无法将中文字符插入到数据库表中的问题。具体表现为尝试插入包含中文字符的数据行时,系统抛出如下错误: ...

    Java数据库高级编程宝典

    10. **分布式事务**: 当系统跨越多个数据库时,了解X/Open XA协议和2PC(两阶段提交)等分布式事务处理机制,对于保证数据一致性至关重要。 以上只是《Java数据库高级编程宝典》中部分核心概念和技能的概述,实际...

    atomikos-util-3.6.4-sources.jar.zip

    在3.6.4版本中,Atomikos引入了多项改进和优化,例如提升了事务处理的性能,增强了对JMS和JPA的支持,以及提供了更丰富的监控和日志记录功能。通过阅读源码,我们可以了解到这些功能的具体实现,以及如何在实际项目...

    jta-1_0_1B-classes.jar

    集成JTA到项目中,开发者需要配置事务管理器,例如使用JBoss Transaction Manager或WebLogic的Transaction Service,并确保所有的持久化层(如JPA、JDBC)都支持XAResource。同时,业务逻辑层需要适当地调用...

    seata-1.3.0.zip

    4. **丰富的生态支持**:Seata兼容Spring Cloud、Dubbo等主流微服务框架,与MyBatis、JPA等持久层框架无缝集成。 总的来说,Seata 1.3.0作为一款强大的分布式事务解决方案,为开发者提供了一站式的服务,帮助他们...

    分布式事务专题-v1.1

    2. **Java Persistence API (JPA)**:JPA作为Java EE的一部分,用于对象/关系映射,允许开发者在Java应用程序中处理数据库事务。它与JTA结合,可以支持分布式事务管理。 3. **Spring框架中的事务管理**:Spring框架...

    java 数据库编程宝典.rar

    书会讨论XA事务、两阶段提交协议,以及在Java中如何处理分布式事务。 8. 数据库安全:涵盖用户权限管理、数据加密、SQL注入防范等方面,帮助开发者理解如何保护数据库的安全。 9. 数据库连接与JNDI(Java Naming ...

    java 事物处理的资源

    5. **Java Persistence API (JPA)**: 虽然JPA主要用于对象关系映射,但它也可以与JTA集成以处理事务。在实体管理工厂配置为使用JTA事务管理时,所有对数据库的更改将在事务上下文中进行。 6. **Java Transaction ...

    jta1.1-doc

    - **JTA与JPA/EJB集成**:在Java EE环境中,JTA与JPA(Java Persistence API)和EJB(Enterprise JavaBeans)结合,实现统一的事务管理。 5. **最佳实践** - **事务边界设定**:明确事务开始和结束的位置,避免长...

Global site tag (gtag.js) - Google Analytics