gpt4 book ai didi

java - 使用 JPA/Hibernate/MySQL 测试 JTA XA 分布式事务

转载 作者:行者123 更新时间:2023-12-04 05:12:29 25 4
gpt4 key购买 nike

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

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

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

但是,每当 Hibernate 尝试访问 TransactionManager 时,我都会收到 NullPointerException。

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

这是我想做的事情:

    // 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:
<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>

最佳答案

我相信当你在 Java EE 容器之外时你不能使用 JTA 事务(或者至少没有简单的方法来做到这一点)。

使用 RESOURCE-LOCAL

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

<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 EE 容器。以下是一些建议,包括 Glassfish 3 的示例:
  • Embededing Glassfish v3 in Unit Test
  • Embedded Glassfish
  • 关于java - 使用 JPA/Hibernate/MySQL 测试 JTA XA 分布式事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14727570/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com