Reputation: 53
I'd like to access two databases in the same application. For each database connection, I have an EntityManagerFactory.
My problem is : I can't merge two Entity in two databases in the same transaction.
There is my beans.xml file :
<context:component-scan base-package="com.example.testdatabase.business" />
<context:component-scan base-package="com.example.testdatabase.service" />
<context:component-scan base-package="com.example.testdatabase.ui" />
<bean id="entityManagerFactoryOrder"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSourceOrder" />
<property name="packagesToScan" value="com.example.testdatabase.business.order" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="validationQuery">select 1 from dual</prop>
<prop key="testOnBorrow">true</prop>
</props>
</property>
<property name="persistenceUnitName" value="orderPU" />
</bean>
<bean id="dataSourceOrder" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:jboss/datasources/OrderCita" />
</bean>
<bean id="transactionManagerOrder" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryOrder" />
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
<bean id="entityManagerFactoryPerson"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSourcePerson" />
<property name="packagesToScan" value="com.example.testdatabase.business.person" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="persistenceUnitName" value="personPU" />
</bean>
<bean id="dataSourcePerson" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:jboss/datasources/Person" />
</bean>
<bean id="transactionManagerPerson" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryPerson" />
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
<tx:annotation-driven/>
My repository :
@Repository
public class Repo {
@PersistenceContext(unitName="orderPU")
@Qualifier(value="entityManagerFactoryOrder")
protected EntityManager emOrder;
@PersistenceContext(unitName="personPU")
@Qualifier(value="entityManagerFactoryPerson")
protected EntityManager emPerson;
public void save() {
Order o = new Order();
o.setTheString("the order");
emOrder.merge(o);
emOrder.close();
Person p = new Person();
p.setTheString("the person");
emPerson.merge(p);
emPerson.close();
}
}
My service :
@Service
public class Manager {
@Autowired
private Repo repo;
@Transactional(value="transactionManagerOrder")
public void save1() {
repo.save();
}
@Transactional(value="transactionManagerPerson")
public void save2() {
repo.save();
}
@Transactional
public void save3() {
repo.save();
}
}
Method "save1()" only merge an Order.
Method "save2()" only merge a Person.
I would like merge an Order and a Person with the same transaction.
Thanks for any help
PS : I'm sorry for my English...
* EDIT *
I tried with bitronix but I have now a nullpointerexception.
I also added this line in the JpaProperties :
org.hibernate.engine.transaction.jta.platform.internal.BitronixJtaPlatform
Here is my new beans.xml file :
<bean class="bitronix.tm.TransactionManagerServices"
factory-method="getConfiguration" id="bitronixConfiguration" />
<bean class="bitronix.tm.TransactionManagerServices" depends-on="bitronixConfiguration"
destroy-method="shutdown" factory-method="getTransactionManager" id="bitronixTransactionManager" />
<bean class="bitronix.tm.resource.jdbc.PoolingDataSource"
destroy-method="close" id="datasourceOrder" init-method="init">
<property name="allowLocalTransactions" value="true" />
<property name="className" value="org.postgresql.xa.PGXADataSource" />
<property name="driverProperties">
<props>
<prop key="password">pwd</prop>
<prop key="url">jdbc:postgresql://localhost:5432/order</prop>
<prop key="user">user</prop>
</props>
</property>
<property name="maxPoolSize" value="5" />
<property name="minPoolSize" value="1" />
<property name="uniqueName" value="exampleDS" />
</bean>
<bean class="bitronix.tm.resource.jdbc.PoolingDataSource"
destroy-method="close" id="datasourcePerson" init-method="init">
<property name="allowLocalTransactions" value="true" />
<property name="className" value="org.postgresql.xa.PGXADataSource" />
<property name="driverProperties">
<props>
<prop key="password">pwd</prop>
<prop key="url">jdbc:postgresql://localhost:5432/person</prop>
<prop key="user">user</prop>
</props>
</property>
<property name="maxPoolSize" value="5" />
<property name="minPoolSize" value="1" />
<property name="uniqueName" value="sampleDS" />
</bean>
<bean id="entityManagerFactoryOrder"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jtaDataSource" ref="datasourceOrder" />
<property name="packagesToScan" value="com.example.testdatabase.business.order" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.transaction.jta.platform">org.hibernate.engine.transaction.jta.platform.internal.BitronixJtaPlatform</prop>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="validationQuery">select 1 from dual</prop>
<prop key="testOnBorrow">true</prop>
</props>
</property>
<property name="persistenceUnitName" value="orderPU" />
</bean>
<bean id="entityManagerFactoryPerson"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jtaDataSource" ref="datasourcePerson" />
<property name="packagesToScan" value="com.example.testdatabase.business.person" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.transaction.jta.platform">org.hibernate.engine.transaction.jta.platform.internal.BitronixJtaPlatform</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="persistenceUnitName" value="personPU" />
</bean>
<bean class="org.springframework.transaction.jta.JtaTransactionManager"
id="transactionManager">
<property name="transactionManager" ref="bitronixTransactionManager" />
<property name="userTransaction" ref="bitronixTransactionManager" />
</bean>
<tx:annotation-driven />
In the Manager class, I removed @Transactional annotation.
In the Repo class, I removed @Qualifier annotation.
The stack trace :
00:47:22,665 SEVERE [com.vaadin.server.DefaultErrorHandler] (http-localhost/127.0.0.1:8080-2) : java.lang.NullPointerException
at org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory.isJoinableJtaTransaction(CMTTransactionFactory.java:63) [hibernate-core-4.1.9.Final.jar:4.1.9.Final]
at org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory.isJoinableJtaTransaction(CMTTransactionFactory.java:39) [hibernate-core-4.1.9.Final.jar:4.1.9.Final]
at org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl.isTransactionJoinable(TransactionCoordinatorImpl.java:295) [hibernate-core-4.1.9.Final.jar:4.1.9.Final]
at org.hibernate.ejb.AbstractEntityManagerImpl.joinTransaction(AbstractEntityManagerImpl.java:1205) [hibernate-entitymanager-4.1.9.Final.jar:4.1.9.Final]
at org.hibernate.ejb.AbstractEntityManagerImpl.postInit(AbstractEntityManagerImpl.java:178) [hibernate-entitymanager-4.1.9.Final.jar:4.1.9.Final]
at org.hibernate.ejb.EntityManagerImpl.<init>(EntityManagerImpl.java:89) [hibernate-entitymanager-4.1.9.Final.jar:4.1.9.Final]
at org.hibernate.ejb.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:179) [hibernate-entitymanager-4.1.9.Final.jar:4.1.9.Final]
at org.hibernate.ejb.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:174) [hibernate-entitymanager-4.1.9.Final.jar:4.1.9.Final]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.6.0_45]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) [rt.jar:1.6.0_45]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) [rt.jar:1.6.0_45]
at java.lang.reflect.Method.invoke(Method.java:597) [rt.jar:1.6.0_45]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.invokeProxyMethod(AbstractEntityManagerFactoryBean.java:376) [spring-orm-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean$ManagedEntityManagerFactoryInvocationHandler.invoke(AbstractEntityManagerFactoryBean.java:519) [spring-orm-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at com.sun.proxy.$Proxy38.createEntityManager(Unknown Source)
at org.springframework.orm.jpa.EntityManagerFactoryUtils.doGetTransactionalEntityManager(EntityManagerFactoryUtils.java:202) [spring-orm-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:211) [spring-orm-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at com.sun.proxy.$Proxy40.merge(Unknown Source)
at com.example.testdatabase.business.repo.Repo.save(Repo.java:29) [classes:]
at com.example.testdatabase.service.Manager.save3(Manager.java:26) [classes:]
at com.example.testdatabase.service.Manager$$FastClassBySpringCGLIB$$3df77bc4.invoke(<generated>) [spring-core-4.1.6.RELEASE.jar:]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) [spring-core-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717) [spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) [spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98) [spring-tx-4.0.5.RELEASE.jar:4.0.5.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262) [spring-tx-4.0.5.RELEASE.jar:4.0.5.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95) [spring-tx-4.0.5.RELEASE.jar:4.0.5.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653) [spring-aop-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at com.example.testdatabase.service.Manager$$EnhancerBySpringCGLIB$$ab725425.save3(<generated>) [spring-core-4.1.6.RELEASE.jar:]
at com.example.testdatabase.TestdatabaseUI$3.buttonClick(TestdatabaseUI.java:56) [classes:]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.6.0_45]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) [rt.jar:1.6.0_45]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) [rt.jar:1.6.0_45]
at java.lang.reflect.Method.invoke(Method.java:597) [rt.jar:1.6.0_45]
at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:508) [vaadin-server-7.5.0.jar:7.5.0]
at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:198) [vaadin-server-7.5.0.jar:7.5.0]
at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:161) [vaadin-server-7.5.0.jar:7.5.0]
at com.vaadin.server.AbstractClientConnector.fireEvent(AbstractClientConnector.java:995) [vaadin-server-7.5.0.jar:7.5.0]
at com.vaadin.ui.Button.fireClick(Button.java:393) [vaadin-server-7.5.0.jar:7.5.0]
at com.vaadin.ui.Button$1.click(Button.java:61) [vaadin-server-7.5.0.jar:7.5.0]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.6.0_45]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) [rt.jar:1.6.0_45]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) [rt.jar:1.6.0_45]
at java.lang.reflect.Method.invoke(Method.java:597) [rt.jar:1.6.0_45]
at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:158) [vaadin-server-7.5.0.jar:7.5.0]
at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:118) [vaadin-server-7.5.0.jar:7.5.0]
at com.vaadin.server.communication.ServerRpcHandler.handleInvocations(ServerRpcHandler.java:313) [vaadin-server-7.5.0.jar:7.5.0]
at com.vaadin.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:202) [vaadin-server-7.5.0.jar:7.5.0]
at com.vaadin.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:95) [vaadin-server-7.5.0.jar:7.5.0]
at com.vaadin.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:41) [vaadin-server-7.5.0.jar:7.5.0]
at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1408) [vaadin-server-7.5.0.jar:7.5.0]
at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:350) [vaadin-server-7.5.0.jar:7.5.0]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:847) [jboss-servlet-api_3.0_spec-1.0.2.Final-redhat-1.jar:1.0.2.Final-redhat-1]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:295) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:149) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
at org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:50) [jboss-as-jpa-7.3.0.Final-redhat-14.jar:7.3.0.Final-redhat-14]
at org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:50) [jboss-as-jpa-7.3.0.Final-redhat-14.jar:7.3.0.Final-redhat-14]
at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:169) [jboss-as-web-7.3.0.Final-redhat-14.jar:7.3.0.Final-redhat-14]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:145) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:97) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:102) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:336) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:856) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:653) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:920) [jbossweb-7.2.2.Final-redhat-1.jar:7.2.2.Final-redhat-1]
at java.lang.Thread.run(Thread.java:662) [rt.jar:1.6.0_45]
Upvotes: 1
Views: 2118
Reputation: 20135
You are currently using local transaction managers that will manage transactions against only one data store at a time. For managing transactions that span across multiple data stores, you will need a JTA compliant transaction manager.
See this sample app for an example of using the Bitronix JTA transaction manager with 2 EntityManager
s.
Upvotes: 1