Frage

Mein Ziel ist es, eine eigenständige Lösung für den Bau von Junit-Tests für lokale und verteilte Transaktionen mit JPA über den Winterschlaf über MySQL zu errichten.

Bisher konnte ich ein XadataSource verwenden, um auf eine XareSource zuzugreifen und die verteilte Transaktion nach dem 2-Phasen-Commit-Protokoll zu verwalten. Ich muss jedoch SQL-Anweisungen direkt ausstellen.

Ich habe versucht, dasselbe zu tun, aber mit JPA 2.0-Persistenz. Ich verwende Simple-JNDI, um eine In-Memory-JNDI-Implementierung zu haben.

Ich bekomme jedoch immer wieder null powerterexception, wenn der Winterschlafangebot versucht, auf den TransactionManager zuzugreifen.

Irgendwelche Ideen? Was fehlt in meiner Konfiguration?

Hier ist was ich gerne tun würde:

    // 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!");
        }
    }

Hier ist Persistenz.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>

War es hilfreich?

Lösung

Ich glaube, Sie können JTA-Transaktionen nicht verwenden, wenn Sie sich außerhalb eines Java EE-Containers befinden (oder zumindest gibt es keine einfache Möglichkeit, dies zu tun).

Verwenden Sie Ressourcen-Local

Es gibt nichts, was JTA in Ihrem Beispiel erfordert: Sie schauen nur eine Datenquelle in einer Java SE-Umgebung auf. Ich denke, Ihre XA-Datenquelle als Ressourcen-Local. würde dein Problem lösen. Setze das in deine persistence.xml:

<persistence-unit name="ContactBookPersistenceUnit" transaction-type="RESOURCE-LOCAL">
    [...]
    <non-jta-data-source>java:/ExampleDS</jta-data-source>

Ich habe diesen Code nicht direkt getestet, aber ich habe einen ähnlichen Ansatz in Webanwendungen verwendet, der für den Apache Tomcat Server geschrieben wurde.

Siehe auch: Arten von Entitymanagers.

Verwenden Sie einen eingebetteten Container

Eine weitere Option, die Sie untersuchen können, beinhaltet das Starten eines eingebetteten Java-EE-Containers in den Jugendstests. Hier sind ein paar Zeiger mit Beispielen für Glasfische 3:

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top