1

有一个 Spring 无 Web 应用程序 Apache James(Java 邮件服务器)。

它使用openjpa。它有一个持久化单元和数据源以及实体管理器工厂定义。

我必须对其进行操作,以便为外部数据库再使用一个持久性单元。

我在 persistence.xml 中又添加了一个单元

<persistence-unit name="James" transaction-type="RESOURCE_LOCAL">
        <!-- Mailbox stuff-->
        <class>org.apache.james.mailbox.jpa.mail.model.JPAMailbox</class>
        <class>org.apache.james.mailbox.jpa.mail.model.JPAUserFlag</class>
        <class>org.apache.james.mailbox.jpa.mail.model.openjpa.AbstractJPAMessage</class>
        <class>org.apache.james.mailbox.jpa.mail.model.openjpa.JPAMessage</class>
        <class>org.apache.james.mailbox.jpa.mail.model.openjpa.JPAMessage</class>
        <class>org.apache.james.mailbox.jpa.mail.model.JPAProperty</class>
        <class>org.apache.james.mailbox.jpa.user.model.JPASubscription</class>
        <class>org.apache.james.domainlist.jpa.model.JPADomain</class>
        <class>org.apache.james.user.jpa.model.JPAUser</class>
        <class>org.apache.james.rrt.jpa.model.JPARecipientRewrite</class>

        <properties>
            <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
            <property name="openjpa.jdbc.MappingDefaults" value="ForeignKeyDeleteAction=cascade, JoinForeignKeyDeleteAction=cascade"/>
            <property name="openjpa.jdbc.SchemaFactory" value="native(ForeignKeys=true)"/>
            <property name="openjpa.jdbc.QuerySQLCache" value="false"/>
        </properties>

    </persistence-unit>


    <persistence-unit name="myPU" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <class>package.EmailAddress</class>
    <class>package.Message</class>
       <properties>
            <property name="javax.persistence.jdbc.user" value="root" />
            <property name="javax.persistence.jdbc.password" value="root" />
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/kepsDb" />
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
            <property name="hibernate.hbm2ddl.auto" value="none" />
            <property name="hibernate.show_sql" value="false" />
            <property name="hibernate.dialect" value=" org.hibernate.dialect.MySQLDialect" />

            <property name="hibernate.max_fetch_depth" value="0"  />
            <property name="hibernate.cache.use_second_level_cache" value="true" />
            <property name="hibernate.cache.use_query_cache" value="false" />
            <property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory" />

            <property name="hibernate.ejb.naming_strategy" value="web.app.persistence.util.AppImprovedNamingStrategy"/>

        </properties>

    </persistence-unit>

我没有在 spring-server.xml 中定义第二个实体管理器工厂,而是生成我自己的内联实体管理器工厂:

EntityManagerFactory emf=Persistence.createEntityManagerFactory("myPU");
        EntityManager entityManager=emf.createEntityManager();
entityManager.getTransaction().begin();

但我得到了例外:

Caused by: org.springframework.beans.FatalBeanException: Unable to execute lifecycle method on beanmailetcontext; nested exception is <openjpa-2.1.0-r422266:1071316 nonfatal user error> org.apache.openjpa.persistence.InvalidStateException: This operation cannot be performed while a Transaction is active.
4

2 回答 2

0

以下代码解释了如何使用 JPA + spring 配置多个持久性单元:

首先,我们在persistence.xml中定义了两个持久化单元,我们分别称它们为unit1和unit2:

<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_1_0.xsd"
  version="1.0">

  <persistence-unit name="Unit1" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <properties>
      <property name="hibernate.archive.autodetection" value="class" />
      <property name="hibernate.connection.driver_class" value="oracle.jdbc.OracleDriver" />
      <property name="hibernate.connection.url" value="jdbc:oracle:thin:@my.company.com:1522:D1" />
      <property name="hibernate.connection.password" value="my_user" />
      <property name="hibernate.connection.username" value="my_password" />
    </properties>
  </persistence-unit>

  <persistence-unit name="Unit2" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <properties>
      <property name="hibernate.archive.autodetection" value="class" />
      <property name="hibernate.connection.driver_class" value="oracle.jdbc.OracleDriver" />
      <property name="hibernate.connection.url" value="jdbc:oracle:thin:@my.company.com:1522:D2" />
      <property name="hibernate.connection.password" value="my_user" />
      <property name="hibernate.connection.username" value="my_password" />
    </properties>
  </persistence-unit>
</persistence>

由于我们处理的是一个独立的 Java 应用程序,我们在 Spring 应用程序上下文中定义了我们的数据源,但对于 Web 应用程序,通常在 persistence.xml 文件本身中定义对这些数据源的 JNDI 引用。

在 application-context.xml 中,这些持久性单元的引用如下:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:tx="http://www.springframework.org/schema/tx"
  xmlns:p="http://www.springframework.org/schema/p"
  xsi:schemaLocation="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/tx
  http://www.springframework.org/schema/tx/spring-tx.xsd">

  <context:annotation-config />
  <tx:annotation-driven />

  <bean id="dataSource1" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="oracle.jdbc.driver.OracleDriver" />
    <property name="jdbcUrl" value="jdbc:oracle:thin:@my.company.com:1521:D1" />
    <property name="user" value="my_user" />
   <property name="password" value="my_password" />
  </bean>

  <bean id="dataSource2" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
    <property name="url" value="jdbc:oracle:thin:@my.company.com:1521:D2" />
    <property name="username" value="my_user" />
    <property name="password" value="my_password" />
  </bean>

  <!-- DEFINITION OF BOTH ENTITY MANAGER FACTORIES -->

  <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource1" />
    <property name="persistenceUnitName" value="Unit1" />
    <property name="persistenceUnitManager" ref="persistenceUnitManager" />
    <property name="jpaVendorAdapter">
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <property name="databasePlatform"
                  value="org.hibernate.dialect.Oracle10gDialect" />
      </bean>
    </property>
  </bean>

  <bean id="entityManagerFactory2"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource2" />
    <property name="persistenceUnitName" value="Unit2" />
    <property name="persistenceUnitManager" ref="persistenceUnitManager" />
    <property name="jpaVendorAdapter">
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <property name="databasePlatform"
                  value="org.hibernate.dialect.Oracle10gDialect" />
      </bean>
    </property>
  </bean>

  <!-- PERSISTENCE UNIT MANAGER and TRANSACTION MANAGERS -->

  <bean id="persistenceUnitManager"
        class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
    <property name="dataSources">
      <map>
        <entry key="d1" value-ref="dataSource1" />
        <entry key="d2" value-ref="dataSource2" />
      </map>
    </property>
  </bean>

  <bean id="transactionManager"
        class="org.springframework.orm.jpa.JpaTransactionManager"
        p:entity-manager-factory-ref="entityManagerFactory" />

  <bean id="abwTransactionManager"
        class="org.springframework.orm.jpa.JpaTransactionManager"
        p:entity-manager-factory-ref="entityManagerFactory2" />
</beans>

现在剩下要做的就是在你的 DAO 中表示 @PersistenceContext,如下所示:

@Required
  @PersistenceContext(unitName = "Unit1")
  public void setEntityManager(final EntityManager entityManager) {
      this.entityManager = entityManager;
  }
于 2012-09-28T16:06:32.750 回答
0

myPU配置为使用 JTA 事务。使用 JTA 时调用entityManager.getTransaction()将导致异常,因为该方法应该与RESOURCE_LOCAL事务类型一起使用。

我不知道您发布的异常消息是否是由于这个原因,但您可以尝试将 of 更改<persistence-unit>myPU

<persistence-unit name="myPU" transaction-type="RESOURCE_LOCAL">

请注意,如果您必须在同一事务中访问两个数据库,则必须使用 JTA。

于 2012-09-28T13:59:21.303 回答