Announcement Announcement Module
Collapse
No announcement yet.
Spring Data Neo4j transactions mixed with Hibernate transactions Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring Data Neo4j transactions mixed with Hibernate transactions

    Hi

    I have a project with a bunch of relational tables mapped with hibernate, using spring managed transactions and everything was working fine until I added Spring Data Neo4j. After that, I could interact with my Neo4j graph db but cannot write to my relational db. No exception, no warning, nothing. Just the request hangs in the call to a method marked with @Transactional.

    I supose that I need to handle differently the transactions, but can't find how to do that.

    Is there a wat yo make SDN transactions work together with Hibernate transactions?

    Thanks in advance

  • #2
    Could you try to use @Neo4jTransactional or @Transactional("neo4jTransactionManager")

    Neo4j defines a transaction manager and only aliases it as transactionManager but your hibernate tx-manager bean definition named "transactionManager" should have precedence.

    Comment


    • #3
      That's exactly the problem, the hibernate transactionManager doesn't take precedence.

      My workaround was to copy the class Neo4jConfiguration, remove the transactionManager alias and use @Neo4jTransactional. With this I can use both transactions managers, but I really don't want to have my own version of that class. What can I do to avoid that conflict?
      Last edited by leonardo.moreno; Apr 25th, 2012, 10:34 AM.

      Comment


      • #4
        I thought the Neo4J transaction manager was a JTA transactionManager. Or maybe you can define a JTA Transaction Manager and wrap the two transaction managers in the JTA one, and then name the JTA one "transactionManager" I had to do something along these lines to have both Spring Data Neo4J and Spring Batch (which has relational tables) in my project.

        Mark

        Comment


        • #5
          Yeah, I had put this in my config

          Code:
          <bean id="neo4jTransactionManager"
              	   class="org.springframework.transaction.jta.JtaTransactionManager">
                  <property name="transactionManager">
                      <bean class="org.neo4j.kernel.impl.transaction.SpringTransactionManager">
                          <constructor-arg ref="graphDatabaseService"/>
                      </bean>
                  </property>
                  <property name="userTransaction">
                      <bean class="org.neo4j.kernel.impl.transaction.UserTransactionImpl">
                          <constructor-arg ref="graphDatabaseService"/>
                      </bean>
                  </property>
                  <property name="allowCustomIsolationLevels" value="true"/>
              </bean>
          And I have

          Code:
          <beans:bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                  <beans:property name="dataSource" ref="dataSource"/>
              </beans:bean>
          for Jdbc to the Batch tables, in order to get both Neo4J and Batch to work together.

          Hope that helps

          Mark

          Comment


          • #6
            Hi Mark, thanks for your time.

            How did you configure neo4j? with <neo4j:config ...>? Because the problem I have is that the Neo4JConfiguration class declares the transaction manager with 2 aliases neo4jTransactionManager and transactionManager and because hibernate looks for the bean named transactionManager, it hangs when trying to the obtain a transaction.

            If that is going to generate a conflict the developers must be aware of that, don't you think?

            Leonardo

            Comment


            • #7
              Originally posted by leonardo.moreno View Post
              Hi Mark, thanks for your time.

              How did you configure neo4j? with <neo4j:config ...>? Because the problem I have is that the Neo4JConfiguration class declares the transaction manager with 2 aliases neo4jTransactionManager and transactionManager and because hibernate looks for the bean named transactionManager, it hangs when trying to the obtain a transaction.

              If that is going to generate a conflict the developers must be aware of that, don't you think?

              Leonardo
              Yeah, I made a bean for my GraphDatabaseService. So I have

              Code:
              <bean id="graphDatabaseService" class="org.neo4j.kernel.EmbeddedGraphDatabase"
                          destroy-method="shutdown">
                      <constructor-arg index="0" value="${neo4j.location}"/>
                      <constructor-arg index="1">
                          <map>
                              <entry key="allow_store_upgrade" value="${neo4j.upgrade}"/>
                          </map>
                      </constructor-arg>
                  </bean>
              
                  <neo4j:config graphDatabaseService="graphDatabaseService"/>
              
                  <neo4j:repositories base-package="com.perfectworldprogramming.eventgate"/>

              Comment


              • #8
                The problem is convenience. If people only use neo4j they want to use @Transactional which by default looks for "transactionManager", that's why the alias is there. I'm not sure how to provide both at the same time, having transactionManager when it is running standalone (aka the alias) and only neo4jTransactionManager when there are two.

                Have you tried to declare your hibernate-tm with primary="true" ? And then use @Neo4jTransactional (if you want to keep them separate).

                If you want the relational db and neo4j participate in the same tx, then it is required to either set up an 2PC TM like atomikos, jotm, the spring tx-manager or one of the appserver-providers. Or you go with the simpler model and configure the ChainedTransactionManager, see the example in CrossStoreNeo4jConfiguration.

                HTH

                Michael

                Comment


                • #9
                  I found this to be quite problematic also. It took me some time to figure out what was going wrong.

                  In the end I settled on this solution for the ChainedTransactionManager

                  Code:
                  <bean id="jpaTransactionManager"
                  	        class="org.springframework.orm.jpa.JpaTransactionManager">
                  	    <property name="entityManagerFactory" ref="localContainerEntityManagerFactoryBean"/>
                  	</bean>
                  	<bean id="xaTransactionManager"
                  	        class="org.springframework.data.neo4j.transaction.ChainedTransactionManager">
                  	    <constructor-arg>
                  	        <list>
                  	            <ref bean="jpaTransactionManager"/>
                  	            <ref bean="transactionManager"/>
                  	            <!--  There is an alias so neo4jTransactionManager and 
                  	            transactionManager refer to the same bean in neo4j:config
                  	            <ref bean="transactionManager"/>-->
                  	        </list>
                  	    </constructor-arg>
                  	</bean>
                  
                  <tx:annotation-driven transaction-manager="xaTransactionManager" />
                  Then I used this (and a few others depending on the calling thread) custom annotation.

                  Code:
                  import java.lang.annotation.ElementType;
                  import java.lang.annotation.Retention;
                  import java.lang.annotation.RetentionPolicy;
                  import java.lang.annotation.Target;
                  
                  import org.springframework.transaction.annotation.Propagation;
                  import org.springframework.transaction.annotation.Transactional;
                  
                  @Target({ElementType.METHOD, ElementType.TYPE})
                  @Retention(RetentionPolicy.RUNTIME)
                  @Transactional(propagation=Propagation.REQUIRED, readOnly=false, value="xaTransactionManager")
                  public @interface TxInit {
                  
                  }
                  Mark

                  Comment


                  • #10
                    Just out of curiosity. Has anyone just tried to declare a "transactionManager" and put it in the xml such that it would be read in after the Neo4J TransactionManager and therefore overwrite the entry of "transactionManager" to be yours?

                    Mark

                    Comment


                    • #11
                      HibernateTransactionManager

                      I found this to be quite problematic also. It took me some time to figure out what was going wrong.

                      In the end I settled on this solution for the ChainedTransactionManager
                      Hi, does it work with JPA?
                      I've tried ChainedTransactionManager with org.springframework.orm.hibernate3.HibernateTransa ctionManager but it works only with "read" operations. Any attempt to write something to DB produces an error

                      Code:
                       [org.springframework.transaction.CannotCreateTransactionException: 
                      Could not open Hibernate Session for transaction; nested exception is java.lang.IllegalStateException: Already value [org.springframework.orm.hibernate3.SessionHolder@13122a1] for key [org.hibernate.impl.SessionFactoryImpl@580334] bound to thread [btpool0-3]]
                      My configuration

                      Code:
                      	<bean id="hbTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
                      		<property name="sessionFactory" ref="prodSessionFactory" />
                      	</bean>
                      
                      	<bean id="chainedTM" class="org.springframework.data.neo4j.transaction.ChainedTransactionManager">
                      		<constructor-arg>
                      			<list>
                      				<ref bean="hbTransactionManager" />
                      				<ref bean="jcrTransactionManager" />
                      				<ref bean="xaTransactionManager" />
                      			</list>
                      		</constructor-arg> 
                      	</bean>
                      Thanks in advance
                      Alexander
                      Last edited by akorotenko; Aug 30th, 2012, 05:53 AM.

                      Comment


                      • #12
                        Could be lots of reasons.

                        How are you creating Sessions in Hibernate. are you using sessionFactory.getCurrentSession() everywhere?
                        Where are you setting your @Transactional in your code?

                        Mark

                        Comment

                        Working...
                        X