1

我正在构建一个需要在两个独立数据库上进行 CRUD 操作的应用程序。事务应用于一个数据库或另一个(从不同时应用于两者……所以我的理解是不需要 JTA)。我的设置与此处的设置非常接近:Multiple database with Spring+Hibernate+JPA

问题:我的服务器(JBoss AS7)启动良好。应用程序从两个数据源读取数据,比如 DS1 和 DS2,但它只能操作来自 DS1 的数据。我可以看到序列(Oracle 11g)正在更新,但没有表更新。没有抛出错误/异常。 我怀疑我的一位事务管理器没有提交。

以下是使用的技术列表和配置设置...

技术栈

  • JBoss AS7
  • 甲骨文 11g
  • 春天 3.1
  • JPA 2
  • 休眠 4.1

持久性-ds1.xml

<persistence 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_2_0.xsd"
version="2.0">
  <persistence-unit name="pu1">
    <class>com.somepackage.EntityA</class>  
    <class>com.somepackage.EntityB</class>  
    <class>com.somepackage.EntityC</class>
    <validation-mode>CALLBACK</validation-mode>
    <properties>
      <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.DefaultNamingStrategy" />
      <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
      <property name="hibernate.hbm2ddl.auto" value="validate" /> 
    </properties>
  </persistence-unit>
</persistence>

持久性-ds2.xml

<persistence 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_2_0.xsd"
version="2.0">
  <persistence-unit name="pu2">
    <class>com.somepackage.EntityD</class>  
    <class>com.somepackage.EntityE</class>  
    <class>com.somepackage.EntityF</class>
    <validation-mode>CALLBACK</validation-mode>
    <properties>
      <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.DefaultNamingStrategy" />
      <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
      <property name="hibernate.hbm2ddl.auto" value="validate" /> 
    </properties>
  </persistence-unit>
</persistence>

应用程序上下文.xml

<?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:jee="http://www.springframework.org/schema/jee"
  xmlns:tx="http://www.springframework.org/schema/tx"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
                      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                      http://www.springframework.org/schema/tx
                      http://www.springframework.org/schema/tx/spring-tx.xsd
                      http://www.springframework.org/schema/jee         
                      http://www.springframework.org/schema/jee/spring-jee.xsd">

  <jee:jndi-lookup id="ds1" jndi-name="java:jboss/datasources/DS1"
    expected-type="javax.sql.DataSource" />
  <jee:jndi-lookup id="ds2" jndi-name="java:jboss/datasources/DS2"
    expected-type="javax.sql.DataSource" />     

  <bean id="em1" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
    <property name="entityManagerFactory" ref="emf1" />
    <property name="persistenceUnitName" value="pu1" />
  </bean>
  <bean id="em2" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
    <property name="entityManagerFactory" ref="emf2" />
    <property name="persistenceUnitName" value="pu2" />
  </bean>

  <bean id="emf1" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceXmlLocation" value="classpath*:META-INF/persistence-ds1.xml"/>
    <property name="dataSource" ref="ds1" />
    <property name="jpaVendorAdapter">
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <property name="showSql" value="true" />
        <property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
      </bean>
    </property>
    <property name="jpaDialect">
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
    </property>
  </bean>
  <bean id="emf2" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceXmlLocation" value="classpath*:META-INF/persistence-ds2.xml"/>
    <property name="dataSource" ref="ds2" />
    <property name="jpaVendorAdapter">
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <property name="showSql" value="true" />
        <property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
      </bean>
    </property>
    <property name="jpaDialect">
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
    </property>
  </bean>

  <tx:annotation-driven transaction-manager="txm1" />
  <tx:annotation-driven transaction-manager="txm2" />

  <bean id="txm1" class="org.springframework.orm.jpa.JpaTransactionManager">
    <qualifier value="txMgr1"/>
    <property name="entityManagerFactory" ref="emf1" />
    <property name="jpaDialect">
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
    </property>
  </bean>
  <bean id="txm2" class="org.springframework.orm.jpa.JpaTransactionManager">
    <qualifier value="txMgr2"/>
    <property name="entityManagerFactory" ref="emf2" />
    <property name="jpaDialect">
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
    </property>
  </bean>   

</beans>

在我的 DAO 中,我引用了类级别的事务管理器,如下所示。

@Transactional("txm1")
public class DAO1 { ... }

@Transactional("txm2")
public class DAO2 { ... }
4

1 回答 1

1

我解决了我的问题!

在我的 applicationContext.xml 中,我删除了以下内容。

<tx:annotation-driven transaction-manager="txm1" />
<tx:annotation-driven transaction-manager="txm2" />

并改用以下内容。

<tx:annotation-driven />

但这就是我认为的踢球者(主要问题)。在我的 DAO 中,我在类级别分配了两个事务管理器。但后来我用我声明我的方法的方式覆盖了它们。

@Transactional(readOnly = false, value = "txm1")
public abstract class AbstractJpaDAO1<T extends Serializable> {
...
@Transactional(readOnly = true)
public T findById(final Long id) {...}

@Transactional
public boolean insert(final T entity) {...}

如您所见,方法上的 @Transaction 注释覆盖了类级别的注释。而且因为没有在方法上指定事务管理器,所以 Spring 默认为“transactionManager”,我没有(现在仍然没有)在我的 applicaitonContext.xml 中声明。因此,它试图使用不存在的事务管理器进行提交。

对于解决方案,我只是删除了方法上的 @Transitional 注释,并将其保留在类级别。

@Transactional(readOnly = false, value = "txm1")
public abstract class AbstractJpaDAO1<T extends Serializable> {
...
public T findById(final Long id) {...}

public boolean insert(final T entity) {...}

现在一切正常!我可以读/写两个独立的数据库。

于 2012-12-07T13:28:10.783 回答