大家好,我有一个有两个不同数据库的应用程序。 第一个数据库用于我们的业务应用程序,第二个数据库属于我们正在使用的框架。
我有一个女经理,我需要访问两个dbs来执行某些操作。 我为我的应用程序配置了两个entityManagerFactory,每个数据源一个,两个事务管理器,每个entityManagerFactory一个......
这是我的配置
我的persistence.xml
<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="ENPIM_BD_PU" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<non-jta-data-source>jdbc/businessDataSource</non-jta-data-source>
<class>it.aicof.projects.enpim.persistence.entities.AccountingRecords</class>
.....
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.show_sql" value="false"/>
</properties>
</persistence-unit>
<persistence-unit name="ENPIM_SERV_PU" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>it.aicof.projects.enpim.persistence.entities.Authusers</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.show_sql" value="false"/>
</properties>
</persistence-unit>
</persistence>
我的app-context.xml
<context:annotation-config/>
<context:component-scan base-package="it.aicof.projects.*"/>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<bean id="dataSourceBusiness" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="${profile.database.driverClassName}" />
<property name="jdbcUrl" value="jdbc:postgresql://${profile.database.hostname}:${profile.database.port}/${profile.database.business}" />
<property name="user" value="${profile.database.username}" />
<property name="password" value="${profile.database.password}" />
<!-- these are C3P0 properties -->
<property name="acquireIncrement" value="${c3p0.acquireIncrement}" />
<property name="initialPoolSize" value="${c3p0.initialPoolSize}" />
<property name="minPoolSize" value="${c3p0.minPoolSize}" />
<property name="maxPoolSize" value="${c3p0.maxPoolSize}" />
<property name="maxIdleTime" value="${c3p0.maxIdleTime}" />
</bean>
<bean id="dataSourceServ" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="${profile.database.driverClassName}" />
<property name="jdbcUrl" value="jdbc:postgresql://${profile.database.hostname}:${profile.database.port}/${profile.database.serv}" />
<property name="user" value="${profile.database.username}" />
<property name="password" value="${profile.database.password}" />
<!-- these are C3P0 properties -->
<property name="acquireIncrement" value="${c3p0.acquireIncrement}" />
<property name="initialPoolSize" value="${c3p0.initialPoolSize}" />
<property name="minPoolSize" value="${c3p0.minPoolSize}" />
<property name="maxPoolSize" value="${c3p0.maxPoolSize}" />
<property name="maxIdleTime" value="${c3p0.maxIdleTime}" />
</bean>
<bean id="transactionManagerBusiness" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory">
<qualifier value="business" />
</bean>
<bean id="transactionManagerServ" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactoryServ">
<qualifier value="serv" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSourceBusiness"
p:jpaVendorAdapter-ref="jpaAdapter">
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
</property>
<property name="persistenceUnitName" value="ENPIM_BD_PU"></property>
</bean>
<bean id="entityManagerFactoryServ"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSourceServ"
p:jpaVendorAdapter-ref="jpaAdapter">
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
</property>
<property name="persistenceUnitName" value="ENPIM_SERV_PU"></property>
</bean>
<bean id="jpaAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
p:database="POSTGRESQL" p:showSql="false"/>
这是我正在使用的代码
我的道歉
@PersistenceContext(unitName = "ENPIM_BD_PU")
protected EntityManager em;
@PersistenceContext(unitName = "ENPIM_SERV_PU")
protected EntityManager emServ;
....
public void edit(AddressBook addressBook) throws NonexistentEntityException, Exception {
try {
addressBook = em.merge(addressBook);
} catch (Exception ex) {
Logger.getLogger(this.getClass().getName()).error("edit", ex);
String msg = ex.getLocalizedMessage();
if (msg == null || msg.length() == 0) {
Integer id = addressBook.getId();
if (findAddressBook(id) == null) {
throw new NonexistentEntityException("The addressBook with id " + id + " no longer exists.");
}
}
throw ex;
}
}
public void createBeneficiaryLoginAccount(String username, String password) throws Exception{
try {
Query q = emServ.createNativeQuery("INSERT INTO authusers(username, passwd, registrationdate, lastaccess, lastpasswordchange, active)" +
" VALUES (?, ?, ?, ?, ?, ?)");
q.setParameter(1, username);
q.setParameter(2, password);
q.setParameter(3, new Date());
q.setParameter(4, new Date());
q.setParameter(5, new Date());
q.setParameter(6, 1);
q.executeUpdate();
}catch (Exception ex) {
Logger.getLogger(this.getClass().getName()).error("createBeneficiaryAccount", ex);
throw ex;
}
}
我的经理
@Override
public void createBeneficiaryAccount(AddressBook addressBook, String password) {
String username = addressBook.getUsername();
try {
AddressBook ab = this.addressBookJpaDAO.findAddressBook(addressBook.getId());
ab.setUsername(username);
//creo l'utente sul db serv e gli assegno il ruolo di beneficiario
this.createBeneficiaryLoginAccount(username, password);
this.createBeneficiaryUsername(ab, password);
} catch (Throwable t) {
Logger.getLogger(this.getClass().getName()).error("", t);
}
}
@Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class, value = "serv")
private void createBeneficiaryLoginAccount(String username, String password) throws Throwable {
try {
//creo l'utente sul db serv e gli assegno il ruolo di beneficiario
this.addressBookJpaDAO.createBeneficiaryLoginAccount(username, password);
} catch (Throwable t) {
Logger.getLogger(this.getClass().getName()).error("createLoginAccount", t);
throw t;
}
}
@Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class, value = "business")
private void createBeneficiaryUsername(AddressBook addressBook, String password) throws Throwable {
try {
this.addressBookJpaDAO.edit(addressBook);
} catch (Throwable t) {
Logger.getLogger(this.getClass().getName()).error("createBeneficiaryUsername", t);
throw t;
}
}
当调用使用第二个entityManager的方法时,我得到异常
2014-11-26 11:10:35,844 ERROR controllers.AddressBookJpaController - createBeneficiaryAccount
javax.persistence.TransactionRequiredException: Executing an update/delete query
at org.hibernate.jpa.spi.AbstractQueryImpl.executeUpdate(AbstractQueryImpl.java:71)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
.....
并调试应用程序我发现当我们尝试使用第二个entityManager时我们有这个错误
Exception occurred in target VM: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:198)
at com.sun.proxy.$Proxy145.getTransaction(Unknown Source)
at it.aicof.projects.enpim.persistence.controllers.AddressBookJpaController.createBeneficiaryLoginAccount(AddressBookJpaController.java:854)
我在网上看一些例子,但所有配置与我的相同。 那么..为什么它不起作用?
出了什么问题?
提前致谢
安德烈
答案 0 :(得分:0)
您在私人方法上注释@Transactional
。这不适用于Spring Aop Proxy Beans。
最快捷的方法是将两种方法都设置为公开
@Transactional("serv")
public void createBeneficiaryLoginAccount(String username, String password) throws Throwable {
try {
//creo l'utente sul db serv e gli assegno il ruolo di beneficiario
this.addressBookJpaDAO.createBeneficiaryLoginAccount(username, password);
} catch (Throwable t) {
Logger.getLogger(this.getClass().getName()).error("createLoginAccount", t);
throw t;
}
}
@Transactional("business")
public void createBeneficiaryUsername(AddressBook addressBook, String password) throws Throwable {
try {
this.addressBookJpaDAO.edit(addressBook);
} catch (Throwable t) {
Logger.getLogger(this.getClass().getName()).error("createBeneficiaryUsername", t);
throw t;
}
}
或者你可能想对AOP使用AspectJ模式,但这是另一层令人头疼的问题恕我直言。
请参阅:Does Spring @Transactional attribute work on a private method?