Search code examples
hibernateneo4jhibernate-ogm

Error flushing data org.neo4j.graphdb.NotInTransactionExcept


I'm trying to make the Dog/Breed example from the docs work for Neo4j persistence. The database is created normally but data can't be flushed, at least that what it seems. I'm getting the error org.neo4j.graphdb.NotInTransactionException in the em.flush() instruction (in the DogBreedRunner.java class above).

I Googled and SOed the issue but really couldn't get around it. Here is my project (I didn't touch the java classes from the docs).

Can someone help please? Let me know if other info are needed.

persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<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="ogm-jpa-tutorial" transaction-type="JTA">
        <!-- Use Hibernate OGM provider: configuration will be transparent -->
        <provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider>
        <properties>
            <property name="hibernate.ogm.datastore.provider" value="neo4j_embedded" />
            <property name="hibernate.ogm.neo4j.database_path" value="C:/Neo4j/NEO4J_HOME/data/graph.db" />

            <!-- defines which JTA Transaction we plan to use -->
            <property name="hibernate.transaction.jta.platform"
                      value="org.hibernate.service.jta.platform.internal.JBossStandAloneJtaPlatform"/>
        </properties>
    </persistence-unit>
</persistence>

Dog.java

package org.hibernate.ogm.examples.gettingstarted.domain;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.TableGenerator;

@Entity
public class Dog {
   @Id @GeneratedValue(strategy = GenerationType.TABLE, generator = "dog")
   @TableGenerator(
      name = "dog",
      table = "sequences",
      pkColumnName = "key",
      pkColumnValue = "dog",
      valueColumnName = "seed"
   )
   public Long getId() { return id; }
   public void setId(Long id) { this.id = id; }
   private Long id;

   public String getName() { return name; }
   public void setName(String name) { this.name = name; }
   private String name;

   @ManyToOne
   public Breed getBreed() { return breed; }
   public void setBreed(Breed breed) { this.breed = breed; }
   private Breed breed;
}

Bread.java

package org.hibernate.ogm.examples.gettingstarted.domain;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

import org.hibernate.annotations.GenericGenerator;

@Entity
public class Breed {

   @Id @GeneratedValue(generator = "uuid")
   @GenericGenerator(name="uuid", strategy="uuid2")
   public String getId() { return id; }
   public void setId(String id) { this.id = id; }
   private String id;

   public String getName() { return name; }
   public void setName(String name) { this.name = name; }
   private String name;
}

DogBreedRunner.java

package org.hibernate.ogm.examples.gettingstarted;

import org.hibernate.ogm.examples.gettingstarted.domain.Breed;
import org.hibernate.ogm.examples.gettingstarted.domain.Dog;
import org.hibernate.ogm.util.impl.Log;
import org.hibernate.ogm.util.impl.LoggerFactory;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.transaction.TransactionManager;
import java.lang.reflect.InvocationTargetException;

public class DogBreedRunner {

    private static final String JBOSS_TM_CLASS_NAME = "com.arjuna.ats.jta.TransactionManager";
    private static final Log logger = LoggerFactory.make();

    public static void main(String[] args) {

        TransactionManager tm = getTransactionManager();

        //build the EntityManagerFactory as you would build in in Hibernate Core
        EntityManagerFactory emf = Persistence.createEntityManagerFactory( "ogm-jpa-tutorial" );

        //Persist entities the way you are used to in plain JPA
        try {
            tm.begin();
            logger.infof( "About to store dog and breed" );
            EntityManager em = emf.createEntityManager();
            Breed collie = new Breed();
            collie.setName( "Collie" );
            em.persist( collie );
            Dog dina = new Dog();
            dina.setName( "Dina" );
            dina.setBreed( collie );
            em.persist( dina );
            Long dinaId = dina.getId();
                        logger.infof( "About to commit" );
            em.flush();
            em.close();
            tm.commit();

            //Retrieve your entities the way you are used to in plain JPA
            logger.infof( "About to retrieve dog and breed" );
            tm.begin();
            em = emf.createEntityManager();
            dina = em.find( Dog.class, dinaId );
            logger.infof( "Found dog %s of breed %s", dina.getName(), dina.getBreed().getName() );
            em.flush();
            em.close();
            tm.commit();

            emf.close();
        } catch ( Exception e ) {
            e.printStackTrace();
        }

    }

    public static TransactionManager getTransactionManager() {
        try {
            Class<?> tmClass = DogBreedRunner.class.getClassLoader().loadClass( JBOSS_TM_CLASS_NAME );
            return (TransactionManager) tmClass.getMethod( "transactionManager" ).invoke( null );
        } catch ( ClassNotFoundException e ) {
            e.printStackTrace();
        } catch ( InvocationTargetException e ) {
            e.printStackTrace();
        } catch ( NoSuchMethodException e ) {
            e.printStackTrace();
        } catch ( IllegalAccessException e ) {
            e.printStackTrace();
        }
        return null;
    }
}

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>hibernate-ogm-documentation-examples</groupId>
    <artifactId>HibernateOMG</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <description>Full code for the Getting Started Guide</description>
    <url>http://ogm.hibernate.org</url>

    <dependencies>
        <!-- Hibernate OGM dependency -->
        <dependency>
            <groupId>org.hibernate.ogm</groupId>
            <artifactId>hibernate-ogm-core</artifactId>
            <version>4.1.0.Beta5</version>
        </dependency>

        <!-- standard APIs dependencies - provided in a Java EE container -->
        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.0-api</artifactId>
            <version>1.0.1.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate.ogm</groupId>
            <artifactId>hibernate-ogm-neo4j</artifactId>
            <version>4.1.0.Beta5</version>
        </dependency>

        <dependency>
            <groupId>org.jboss.spec.javax.transaction</groupId>
            <artifactId>jboss-transaction-api_1.1_spec</artifactId>
            <version>1.0.0.Final</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>javax.persistence</artifactId>
            <version>2.1.0</version>
            <type>jar</type>
        </dependency>       

        <!-- JBoss Transactions dependency -->
        <dependency>
            <groupId>org.jboss.jbossts</groupId>
            <artifactId>jbossjta</artifactId>
            <version>4.16.4.Final</version>
        </dependency>


    </dependencies>
</project>

Exception:

org.neo4j.graphdb.NotInTransactionException at org.neo4j.kernel.impl.persistence.PersistenceManager.getCurrentTransaction(PersistenceManager.java:284) at org.neo4j.kernel.impl.persistence.PersistenceManager.getResource(PersistenceManager.java:249) at org.neo4j.kernel.impl.persistence.PersistenceManager.currentKernelTransactionForReading(PersistenceManager.java:230) at org.neo4j.kernel.impl.core.ThreadToStatementContextBridge.transaction(ThreadToStatementContextBridge.java:53) at org.neo4j.kernel.impl.core.ThreadToStatementContextBridge.instance(ThreadToStatementContextBridge.java:47) at org.neo4j.kernel.impl.core.NodeProxy.setProperty(NodeProxy.java:203) at org.hibernate.ogm.datastore.neo4j.Neo4jDialect.putTupleOperation(Neo4jDialect.java:373) at org.hibernate.ogm.datastore.neo4j.Neo4jDialect.applyOperation(Neo4jDialect.java:355) at org.hibernate.ogm.datastore.neo4j.Neo4jDialect.applyTupleOperations(Neo4jDialect.java:348) at org.hibernate.ogm.datastore.neo4j.Neo4jDialect.updateTuple(Neo4jDialect.java:123) at org.hibernate.ogm.persister.OgmEntityPersister.insert(OgmEntityPersister.java:928) at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:104) at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:463) at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:349) at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:350) at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:56) at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1222) at org.hibernate.jpa.spi.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:1335) at org.hibernate.ogm.jpa.impl.OgmEntityManager.flush(OgmEntityManager.java:119) at org.hibernate.ogm.examples.gettingstarted.DogBreedRunner.main(DogBreedRunner.java:40)


Solution

  • I posted the question to the official forums and I got the right answer.

    • Remove the "hibernate.transaction.jta.platform" property from your persistence.xml. The reason for this is that we need a special implementation for Neo4j atm. (this should hopefully change in the future). But Hibernate OGM will use JBossStandAloneJtaPlatform as default for all stores except Neo4j anyways, so there is no need to specify it.
    • Use the following method to retrieve the transaction manager (it needs to be done after the EMF has been bootstrapped):
    private static TransactionManager extractJBossTransactionManager(EntityManagerFactory factory) {
        SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) ( (HibernateEntityManagerFactory) factory).getSessionFactory();
         return sessionFactory.getServiceRegistry().getService( JtaPlatform.class ).retrieveTransactionManager(); 
    }
    

    Should you btw. work with several transactions in a row using the same entity manager, you need to invoke EntityManager#joinTransaction() after the transaction has begun.

    Source: https://forum.hibernate.org/viewtopic.php?f=31&t=1035764&p=2480105