Announcement Announcement Module
Collapse
No announcement yet.
Multiple EntityManagerFactory beans with JTA transaction manager Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Multiple EntityManagerFactory beans with JTA transaction manager

    Hi,

    I am trying to configure two entityManagerFactories in a single context file. While one of these is a bean managed transaction mode, the other is an externally configured JTA mode pf transaction management.

    This is the relevant portion of my Spring config file:

    Code:
    <beans>
    	.......
    	<bean id="jndi.datasource"
    		class="org.springframework.jndi.JndiObjectFactoryBean">
    		<property name="jndiName" value="jdbc/TestDataSource" />
    	</bean>
    
    	<bean id="localEntityManagerFactory"
    		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    		<property name="dataSource" ref="jndi.datasource" />
    		<property name="persistenceUnitName"
    			value="myApp1" />
    		<property name="jpaVendorAdapter">
    			<bean
    				class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    				<property name="showSql" value="true" />
    			</bean>
    		</property>
    	</bean>
    
    	<bean id="localDAO"
    		class="com.simpletest.LocalDAO">
    		<property name="entityManagerFactory"
    			ref="localEntityManagerFactory" />
    	</bean>
    	.......
    	.......
    	<bean id="jta.datasource" class="org.springframework.jndi.JndiObjectFactoryBean">
    		<property name="jndiName" value="jdbc/TestDataSource" />
    	</bean>
      
       
          <bean id="jta.entityManagerFactory" 
    		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
            <property name="dataSource" ref="jta.datasource" />
            <property name="persistenceUnitName" value="jtaApp1" />
            <property name="jpaVendorAdapter">
                <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" >
                	<property name="showSql" value="true" />
                </bean>
            </property>
    		<property name="jpaPropertyMap">
    			<map>
    				<entry key="javax.persistence.transactionType" value="JTA" />
    				<entry key="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.WebSphereExtendedJTATransactionLookup"/>
    				<entry key="hibernate.current_session_context_class" value="thread"/>
    			</map>
    		</property>
    	</bean>
    
    	<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
    
    	<bean id="transactionManager" class="org.springframework.transaction.jta.WebSphereUowTransactionManager" />
    
    	<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="false" />
    	.......
           <bean id="managedDao" class="com.simpletest.ManagedDAO" />
    	.......
    </beans>
    In the local dase, my DAO gets the required EntityManagerFactory injected and creates the EntityManager manually asand when required.

    In the managed case, the ManagedDAO just has a @PersistenceContext annotation where Spring sets the EntityManager. The integration of these two is causing a problem as Spring appears to not find a default EMF to be used for a managed dao:

    Code:
    Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [javax.persistence.EntityManagerFactory] is defined: expected single bean but found 2
    	at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findDefaultEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:513)
    	at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:473)
    	at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.resolveEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:584)
    	at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.getResourceToInject(PersistenceAnnotationBeanPostProcessor.java:575)
    	at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:192)
    	at org.springframework.beans.factory.annotation.InjectionMetadata.injectMethods(InjectionMetadata.java:117)
    	at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.postProcessPropertyValues(PersistenceAnnotationBeanPostProcessor.java:321)
    Is there a recommended way for such configurations? Or is there a way to mark the managed entityManagerFactory bean to be picked up by the JTA transaction manager?

    Thanks.

  • #2
    Use defaultPersistenceUnitName

    The answer to this is to provide a default persistence unit name to the Annotation Processor:

    Code:
    	<bean
    		class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" >
    		<property name="defaultPersistenceUnitName" value="Authorization"/>
    	</bean>
    Thanks.

    Comment


    • #3
      But how would we then use a second persistence unit? Surely it would always default to the default you've just set?

      Comment


      • #4
        i had the same problem and was editing the config files for about 2 days with no success. The easiest way is the simplest!!!

        This config worked for me:
        persistence.xml:
        Code:
        <?xml version="1.0" encoding="UTF-8"?>
        <persistence version="1.0" 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_1_0.xsd">
        <persistence-unit name="pu1" transaction-type="JTA">
            <provider>org.hibernate.ejb.HibernatePersistence</provider>
            <jta-data-source>jdbc/PU1</jta-data-source>
            <exclude-unlisted-classes>false</exclude-unlisted-classes>
          </persistence-unit>
         <persistence-unit name="pu2" transaction-type="JTA">
            <provider>org.hibernate.ejb.HibernatePersistence</provider>
            <jta-data-source>jdbc/PU2</jta-data-source>
            <exclude-unlisted-classes>false</exclude-unlisted-classes>
            </properties>
          </persistence-unit>
        </persistence>

        spring-config-persistence.xml:
        Code:
        <tx:jta-transaction-manager />
            <tx:annotation-driven/>
        
            <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" >
               <property name="persistenceUnits">
                   <map>
                       <!--
                       add PersistenceUnit:
                            persistence.xml anpassen
                            web.xml persistence-unit-ref hinzufügen.
                            fertig
                       -->
                       <entry key="pu1" value="persistence/PU1"/>
                       <entry key="pu2" value="persistence/PU2"/>
                   </map>
               </property>
               <property name="defaultPersistenceUnitName" value="pu1"/>
            </bean>
        
            <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
               <property name="persistenceUnitName" value="pu1"/>
        <!-- u need to probs to use JTATransactionManager -->
              <property name="jpaVendorAdapter">
                    <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                        <property name="showSql" value="false"/>
                        <property name="database" value="ORACLE"/>
                    </bean>
                </property>
                <property name="jpaProperties">
                    <props>
                        <prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</prop>
                        <prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.SunONETransactionManagerLookup</prop>
                    </props>
                </property>
            </bean>

        finally a mapping in the web.xml:
        <web-app>
        <persistence-unit-ref>
        <persistence-unit-ref-name>persistence/PU1</persistence-unit-ref-name>
        <persistence-unit-name>pu1</persistence-unit-name>
        </persistence-unit-ref>
        <persistence-unit-ref>
        <persistence-unit-ref-name>persistence/PU2</persistence-unit-ref-name>
        <persistence-unit-name>pu2</persistence-unit-name>
        </persistence-unit-ref>
        </web-app>



        Running perfectly on Glassfish with spring 2.5.6

        Inject your EntityManager with @PersistenceContext(unitName="pu1|pu2")
        and add @Transactional where needed.

        Comment


        • #5
          Using multiple EMF for sharding - txn handling

          Hi,

          We've a Spring project that was using JPA with Hibernate , but now needs to work with a sharded DB. Here, we determine the DB instance to connect to within the DAO method, and get the corresponding emf + em. Earlier, there was a single em for the DAO injected via @PersistenceContext. Based on above configurations, i managed to get it working like :


          Code:
          public void saveBizEntity(BizEntity biz) {
          
          // logic to select the correct emf (entityManagerFactory_shard1, emf_shard2 etc.) based on bizEntity values 
          ... 
           entityManager = entityManagerFactory_shard2.createEntityManager();
                      entityManager.getTransaction().begin();
                      entityManager.persist(bizEntity); //bizEntity maps to multiple tables
                      entityManager.getTransaction().commit();
                      entityManager.close();
          }

          Before sharding, we didnt have to worry abt txn handling since we used @Transactional and <tx:annotation-driven/>. Is there any similar Spring configuration by which i can achieve the same effect in this context without having to give custom AOP code?

          Comment

          Working...
          X