首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用JPA / Hibernate / MySQL测试JTA分布式事务

用JPA / Hibernate / MySQL测试JTA分布式事务
EN

Stack Overflow用户
提问于 2013-02-06 19:09:46
回答 1查看 4.1K关注 0票数 2

我的目标是拥有一个独立的解决方案,用于使用MySQL上的Hibernate上的JPA为本地和分布式事务构建JUnit测试。

到目前为止,我已经能够使用XADataSource访问XAResource并遵循两阶段提交协议管理分布式事务。但是,我必须直接发出SQL语句。

我一直在尝试做同样的事情,但使用的是JPA 2.0持久性。我使用simple-jndi来实现内存中的JNDI。

然而,每当Hibernate试图访问TransactionManager时,我总是得到NullPointerException。

有什么想法吗?我的配置中缺少什么?

这是我想要做的:

代码语言:javascript
复制
    // Create the XA datasource instance directly
    MysqlXADataSource mysqlDS = new MysqlXADataSource();
    mysqlDS.setServerName("localhost");
    mysqlDS.setDatabaseName("test");
    mysqlDS.setUser("root");
    mysqlDS.setPassword("rootroot");

    // setup local JNDI
    final XADataSource xaDataSource = (XADataSource) mysqlDS;

    InitialContext ctx = new InitialContext(  );
    ctx.bind("java:/ExampleDS", xaDataSource);

    {
        System.out.println("Lookup...");
        Object o = ctx.lookup("java:/ExampleDS");
        System.out.println("Test lookup: " + o);
    }

    // XID - transaction ID

    // global transaction identifier
    // -      --          --
    byte[] gtrid = new byte[] { 0x44, 0x11, 0x55, 0x66 };

    // branch qualifier
    // -      ----
    byte[] bqual = new byte[] { 0x00, 0x22, 0x00 };

    // combination of gtrid and bqual must be unique

    Xid xid1 = new com.mysql.jdbc.jdbc2.optional.MysqlXid(gtrid, bqual, 0);
        // byte[] gtrid, byte[] bqual, int formatId


    // before transaction
    {
        XADataSource xaDS = (XADataSource) ctx.lookup("java:/ExampleDS");

        XAConnection xaconn = xaDS.getXAConnection();
        Connection conn = xaconn.getConnection();
        XAResource xares = xaconn.getXAResource();

        /* the transaction begins */
        System.out.println("Start transaction");
        xares.start(xid1, TMNOFLAGS);
    }


    // JPA code

    EntityManagerFactory emf;
    emf = Persistence.createEntityManagerFactory("MyPersistenceUnit"); // defined in persistence.xml
    EntityManager em = emf.createEntityManager();

    // System.out.println("begin");
    // em.getTransaction().begin();

    System.out.println("new ContactBook");
    ContactBook contactBook = new ContactBook("Alice");

    System.out.println("addContacts");
    contactBook.addContact("Alice", 100100100);
    contactBook.addContact("Bob", 200200200);
    contactBook.addContact("Charlie", 300300300);

    System.out.println("persist");
    em.persist(contactBook);
    //em.flush();

    // System.out.println("commit");
    // em.getTransaction().commit();


    // after transaction
    {
        XADataSource xaDS = (XADataSource) ctx.lookup("java:/ExampleDS");
        System.out.println("xaDS " + xaDS);

        XAConnection xaconn = xaDS.getXAConnection();
        Connection conn = xaconn.getConnection();
        XAResource xares = xaconn.getXAResource();

        System.out.println("End transaction");
        xares.end(xid1, TMSUCCESS);

        // prepare, commit

        System.out.print("Prepare... ");
        int rc1 = xares.prepare(xid1);
        System.out.println(xaString(rc1));

        if (rc1 == XA_OK) {
            System.out.println("Commit");
            xares.commit(xid1, /*onePhase*/ false);
        } else if(rc1 == XA_RDONLY) {
            System.out.println("Commit no necessary - operations were read only");
        } else {
            throw new IllegalStateException("Unexpected case!");
        }
    }

下面是persistence.xml:

代码语言:javascript
复制
<persistence xmlns="http://java.sun.com/xml/ns/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">
<persistence-unit name="ContactBookPersistenceUnit" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>java:/ExampleDS</jta-data-source>
    <properties>
        <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
        <property name="hibernate.hbm2ddl.auto" value="create" />
        <property name="hibernate.show_sql" value="true" />

        <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/>

        <property name="current_session_context_class" value="jta"/>
        <!-- <property name="hibernate.session_factory_name" value="java:/hibernate/MySessionFactory"/> optional -->

        <property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory"/>
        <property name="hibernate.connection.release_mode" value="auto"/>
        <!-- setting above is important using XA-DataSource on SQLServer,
            otherwise SQLServerException: The function START: has failed. No transaction cookie was returned.-->

        <!--property name="hibernate.cache.use_second_level_cache" value="true"/-->
        <!--property name="hibernate.cache.use_query_cache" value="true"/-->

        <!-- property name="hibernate.cache.region.factory_class"   value="org.hibernate.cache.infinispan.InfinispanRegionFactory"/-->
    </properties>
</persistence-unit>

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-08-03 00:29:46

我认为当您在Java容器之外时,不能使用JTA事务(或者至少没有简单的方法可以做到这一点)。

使用资源本地

在您的示例中没有任何需要JTA的东西:您只是在Java SE环境中查找数据源。我认为将XA数据源声明为资源本地可以解决您的问题。把这个放到你的persistence.xml

代码语言:javascript
复制
<persistence-unit name="ContactBookPersistenceUnit" transaction-type="RESOURCE-LOCAL">
    [...]
    <non-jta-data-source>java:/ExampleDS</jta-data-source>

我没有直接测试这段代码,但我在为Apache Tomcat服务器编写的web应用程序中使用了类似的方法。

另请参阅:Types of EntityManagers

使用嵌入式容器

您可能会研究的另一个选项涉及在JUnit测试中启动嵌入式Java容器。以下是几个指针,以及Glassfish 3的示例:

  • Embededing Glassfish v3 in Unit Test
  • Embedded Glassfish
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14727570

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档