Announcement Announcement Module
Collapse
No announcement yet.
Problem Getting Hibernate(JPA) and Neo4j Transactions to work (no cross store) Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Problem Getting Hibernate(JPA) and Neo4j Transactions to work (no cross store)

    Hello there,

    I'm having problems to understand how to get a JPA Transaction-manager and a JTA Transaction-manager to work in one Application. I don't want "combined" transactions, just two completely independent data stores with their own transactions.

    What I've got so far:

    Code:
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    		<property name="entityManagerFactory" ref="entityManagerFactory">
    		</property>
    		<property name="nestedTransactionAllowed" value="true" />
    		<property name="dataSource" ref="dataSource" />
    	</bean>
    
    <bean id="entityManagerFactory" .../>
    <bean id="dataSource" .../>
    
    <tx:annotation-driven order="1" />
    
    <bean id="graphDb" class="org.neo4j.kernel.EmbeddedGraphDatabase"
    		destroy-method="shutdown" lazy-init="false">
    		<constructor-arg>
    			<value>neo4j-db</value>
    		</constructor-arg>
    	</bean>
    
    	<bean id="neo4jTransactionManagerService"
    		class="org.neo4j.kernel.impl.transaction.SpringTransactionManager">
    		<constructor-arg ref="graphDb" />
    	</bean>
    	<bean id="neo4jUserTransactionService" class="org.neo4j.kernel.impl.transaction.UserTransactionImpl">
    		<constructor-arg ref="graphDb" />
    	</bean>
    
    	<bean id="neo4jTransactionManager"
    		class="org.springframework.transaction.jta.JtaTransactionManager">
    		<property name="transactionManager" ref="neo4jTransactionManagerService" />
    		<property name="userTransaction" ref="neo4jUserTransactionService" />
    	</bean>
    
    
    	<tx:annotation-driven transaction-manager="neo4jTransactionManager"
    		order="2" />
    	
    
    	<datagraph:config graphDatabaseService="graphDb" />
    From my understanding, the tx:annotation-driven tags are only important in conjunction with the @Transactional annotation.

    Problem is, I don't even get Spring to start up without errors.

    What is happening is that a org.springframework.data.graph.neo4j.config.Config urationCheck is created with a JpaTransactionManager as second argument.

    I don't even understand how this can be as the method public PlatformTransactionManager transactionManager() in Neo4jConfiguration which is called as the second Constructor argument returns either a JtaTransactionManager or a ChainedTransactionManager but maybe there is some Aspect-Magic involved that I don't understand.

    However, question is, what do I have to change in my Configuration to tell the Neo4jConfiguration to use neo4jTransactionManager?

    What I can't do is define an alias transactionManager -> neo4jTransactionManager because then the existing (and working JPA stoarage freaks out.

    Thanks all,
    Bjoern

  • #2
    Could you list your errors and your configuration file?

    The Neo4jConfiguration methods are using existing libraries. So what happens if you try to access transactionManager bean in the spring config and see what type it is?

    Perhaps you could also provide a stripped down demo project for investigation?

    Thanks so much

    Michael

    Comment


    • #3
      Hi Michael,

      thanks for your help.

      I've created a TestCase (attached (hope so ).

      Simply start it with mvn clean package exec:java and watch the beautifull Exception

      Bjoern

      Attachment
      Attached Files

      Comment


      • #4
        Dammit, the forum just remove the content of my post.

        Ok, again: I fixed your config by deleting lots of stuff, passing EMF to the datagraph:config and adding <tx:annotation-driven mode=aspectj>

        Code below:
        HTML Code:
        <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns="http://www.springframework.org/schema/beans"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
               xmlns:datagraph="http://www.springframework.org/schema/data/graph"
               xsi:schemaLocation="
        		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
        		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
        		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
        		http://www.springframework.org/schema/data/graph http://www.springframework.org/schema/data/graph/datagraph-1.0.xsd">
        
        
            <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
                <property name="dataSource" ref="dataSource"/>
                <property name="persistenceXmlLocation" value="classpath:META-INF/test-persistence.xml"/>
                <property name="persistenceUnitName" value="test"/>
                <property name="jpaVendorAdapter">
                    <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                        <property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect"/>
                        <property name="showSql" value="false"/>
                        <property name="generateDdl" value="true"/>
                        <property name="database" value="HSQL"/>
                    </bean>
                </property>
            </bean>
        
        
            <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
                <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
                <property name="url" value="jdbc:hsqldb:mem:testdb"/>
                <property name="username" value="sa"/>
                <property name="password" value=""/>
            </bean>
        
            <bean id="testDao" class="test.TestDao">
                <property name="entityManagerFactory" ref="entityManagerFactory"/>
            </bean>
        
            <context:spring-configured/>
            <context:annotation-config/>
        
            <tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
            <datagraph:config storeDirectory="target/neo4j-db" entityManagerFactory="entityManagerFactory"/>
            <datagraph:repositories base-package="test"/>
        
            <context:component-scan base-package="test"/>
        </beans>

        Comment


        • #5
          Thanks, but...

          The test case might work now, but I really don't understand how. Furthermore I don't think it will work in my real project.

          Now there is no transactionManager defined at all, so it is created by spring. What kind of transactionManager will it be? Spring-JTA oder JPA?

          Additionally, the entityManagerFactory is passed to the neo4j config. I really don't want this as it is configured to be (and used as) JPA/Hiberneta specific.

          Again, I don't want to merge JPA and neo4j transactions/adapters/whatever in my application (it's nice to know it would be possible, but I don't want it at this point).

          I would like to configure two independent application parts, one using neo4j, one using JPA without sharing any transaction-related resources.

          That's why I configured two transactionManagers manually, which apparently I did the wrong way.

          Now, how is it done right ?

          Thanks,
          Bjoern

          Comment


          • #6
            Ok, thanks for the clarification. Will get back to you.

            Michael

            Comment


            • #7
              Good catch. We just recently discussed this with Jürgen Höller in Linz.
              If the transaction managers should co-exist you have to define the two of them with different names.
              Then for the @Transactional you can provide an identifier that maps to the bean name or qualifier @Transactional("neo4jTransactionManager").

              As @Transactional is a meta annotation we plan to provide a @Neo4jTransactional annotation out of the box with SDN that uses this one.

              HTH

              Michael

              Comment


              • #8
                Hi Michael,

                sorry for the delayed answer, was on Holiday.

                Please see my first post, my problem is not about @Transactional annotations, I know I can pass a specific manager to them.

                If you can find the time, please look at what happens in my example. IIRC there is not even a @Transactional annotation involved all.

                I also already defined two different transaction managers.

                My problem is that right at startup of the spring context the neo4j configuration gets the wrong tx-manager injected (JPA) and I don't know how to configure neo4j to not use "transactionManager" which I think is some kind of default bean name somewhere. But in my case "transactionManager" is the (JPA) one.

                I just can't find the right place to put the information to use "neo4jTransactionManager" in the datagraph config.

                Thanks,
                Bjoern

                Comment


                • #9
                  I changed that for SDN2.0, neo4j declares and also uses neo4jTransactionManager, and also provides a @Neo4jTransactional annotation to explicitely use that one.

                  Could you try the SDN2.0 M1 and get back with your results?

                  Thanks

                  Michael

                  Code:
                  from Neo4jConfiguration:
                      @Bean(name = {"neo4jTransactionManager","transactionManager"})
                      @Qualifier("neo4jTransactionManager")
                  	public PlatformTransactionManager neo4jTransactionManager() {
                          return createJtaTransactionManager();
                  	}
                  
                  
                      @Bean
                      public MappingInfrastructure mappingInfrastructure() throws Exception {
                          MappingInfrastructure infrastructure = new MappingInfrastructure();
                     ....
                          infrastructure.setTransactionManager(neo4jTransactionManager());
                          infrastructure.setGraphDatabase(graphDatabase());
                  
                  ...        return infrastructure;
                      }
                  
                  
                  @Transactional("neo4jTransactionManager")
                  @Retention(RetentionPolicy.RUNTIME)
                  @Target({ElementType.METHOD,ElementType.TYPE})
                  public @interface Neo4jTransactional {
                  }

                  Comment


                  • #10
                    Thanks for the clarification, didn't notice there was a new version.

                    Finally, after one day of refactoring, I got it working.

                    But there is still one thing I don't understand. Maybe you could explain why it is working this way:

                    If I declare the JPA TM this way:

                    <bean id="transactionManager"... org.springframework.orm.jpa.JpaTransactionManager/>
                    <tx:annotation-driven order="1" transaction-manager="transactionManager"/>
                    <bean id="neo4jTransactionManager" .../>
                    <tx:annotation-driven transaction-manager="neo4jTransactionManager" order="2" />

                    In other words if there is a TM named transactionManager, every @Transactional annotation (without a qualifier) wraps a JTA TM.


                    Only if I define the standard (JPA) TM this way:

                    <bean id="someNoneStandardNameTransactionManager"... org.springframework.orm.jpa.JpaTransactionManager/>
                    <tx:annotation-driven order="1" transaction-manager="someNoneStandardNameTransactionManager"/>

                    In other words if there is NO such TM named transactionManager, it works.

                    Changing the order does not change the behaviour at all.

                    I don't understand what is happening in the first case described:

                    - TM named transactionManager defined
                    - tx-annotation-driven defined with order 1 and that manager
                    - usage of @Transactional without parameter

                    -> still the wrong (JTA) TM gets wrapped.

                    Bjoern

                    Comment


                    • #11
                      See appended file for working/ non working version.

                      applicationContext.xml contains both cases, non working version is active.

                      Comment

                      Working...
                      X