【问题标题】:Injecting one of the two @PersistenceContext注入两个@PersistenceContext 之一
【发布时间】:2018-09-26 14:29:57
【问题描述】:

考虑拥有两个实体管理器工厂:

<bean id="writeEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">...</bean>
<bean id="readOnlyEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">...</bean>

然后我想要两个 Bean,我将向其中注入正确的持久性上下文:

<bean id="readOnlyManager" class="..MyDatabaseManager">
<bean id="writeManager" class="..MyDatabaseManager">

bean 看起来像:

public class MyDatabaseManager {

    private javax.persistence.EntityManager em;

    public EntityManager(javax.persistence.EntityManager em) {
        this.em = em;
    }
    ...
}

这显然不行,因为EntityManager不是bean,不能这样注入:

No qualifying bean of type 'javax.persistence.EntityManager' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

如何在 bean 中限定正确的 EntityManager?我以前用@PersistenceContext注解,但是这个不能用,需要注入。

如何为此类 Bean 指定 PersistenceContext?

更新:我的问题是如何通过 XML 而不是通过注释注入带有限定符的 PersistenceContext。

【问题讨论】:

  • 你可以注入 EntityManagerFactory
  • 这是个好主意吗?获得 enitymanager 的唯一方法是通过 emFactory.getNativeEntityManagerFactory().createEntityManager() 创建一个新的。我不确定创建一个新的是否是个好主意?
  • @Vojtěch 这里有详细信息codingpedia.org/ama/…

标签: spring hibernate jpa


【解决方案1】:

persistence.xml(2 个不同实体管理器的 2 个持久性单元,基于您的持久性提供程序,我在这里使用 HibernatePersistence)

<persistence version="2.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_2_0.xsd">
   <persistence-unit name="pu1">
      <provider>org.hibernate.ejb.HibernatePersistence</provider>
   </persistence-unit>

   <persistence-unit name="pu2">
      <provider>org.hibernate.ejb.HibernatePersistence</provider>
   </persistence-unit>   
</persistence>

确保使用属性 persistenceUnitName 将持久性单元分配给实体管理器

    <bean id="writeEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
            <property name="persistenceXmlLocation" value="classpath: of yout persistence xml" />
            <property name="persistenceUnitName" value="pu1" />  
             .....other configuration of em..  
    </bean>

其他 em 也一样。

现在,使用 MyDatabaseManager 的构造函数注入来注入 EntityManager(使用限定符名称 ex. writeEntityManagerFactory )

<bean id="mdm" class="MyDatabaseManager">
     <constructor-arg ref = "writeEntityManagerFactory"/>
</bean>

【讨论】:

  • 我已经澄清我需要在 XML 中定义限定符,而不是通过注释在代码中:How can I qualify correct EntityManager in the bean? I used to use @PersistenceContext annotation, but this is not usable as I need to inject it.
  • 这还不够——如何在不创建新实体的情况下从工厂获取实体管理器?我想使用已经创建的那个。
【解决方案2】:

假设您使用 spring 来管理事务我会做的是 2 个不同的事务管理器,然后在我的服务中我会使用最合适的事务管理器,如下所示:

配置部分

@Bean
public LocalContainerEntityManagerFactoryBean writeEntityManagerFactory() {

    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    //Your configuration here
    return factory;
}

@Bean(name={"writeTx"})
public PlatformTransactionManager writeTransactionManager() {

    JpaTransactionManager txManager = new JpaTransactionManager();
    txManager.setEntityManagerFactory(writeEntityManagerFactory().getObject());
    return txManager;
}

@Bean
public LocalContainerEntityManagerFactoryBean readEntityManagerFactory() {

    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    //Your configuration here
    return factory;
}

@Bean(name={"readTx"})
public PlatformTransactionManager readTransactionManager() {

    JpaTransactionManager txManager = new JpaTransactionManager();
    txManager.setEntityManagerFactory(readEntityManagerFactory().getObject());
    return txManager;
}

服务层

@Transactional(value="readTx")
public List<Object> read(){
    //Your read code here
}

@Transactional(value="writeTx")
public void write(){
    //Your write code here
}

更新答案 我误解了这个问题。

在你的配置类中你可以定义:

@Bean
    public LocalContainerEntityManagerFactoryBean writeEntityManagerFactory() {

        LocalContainerEntityManagerFactoryBean em  = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource());
        em.setPackagesToScan(new String[] { "models" });
        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(hibProps());
        em.setPersistenceUnitName("writer");
        return em;
    }
    @Bean
    public LocalContainerEntityManagerFactoryBean readEntityManagerFactory() {

        LocalContainerEntityManagerFactoryBean em  = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource());
        em.setPackagesToScan(new String[] { "models" });
        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(hibProps());
        em.setPersistenceUnitName("reader");
        return em;
    }   

请查看PersistenceUnitName

然后你可以通过以下方式注入它们:

@PersistenceContext(unitName="writer")
private EntityManager emWriter;

@PersistenceContext(unitName="reader")
private EntityManager emReader;

我刚刚测试过,一切都很好

安杰洛

【讨论】:

  • 这不能回答我的问题。我不担心 TransactionManager,而是 PersistenceContext。
  • 感谢您更新您的答案,但同样:我无法使用注释 @PersistenceContext 插入它们,因为我想通过 XML 配置注入它。与其他答案相同的问题。
【解决方案3】:

我想你正在尝试将 entityManager 注入到你的管理器类中

public class MyDatabaseManager {

// where you need to qualify your injection    
private javax.persistence.EntityManager em;

    public EntityManager(javax.persistence.EntityManager em) {
        this.em = em;
    }
    ...
}

这是我项目的工作代码

  1. META-INF 文件夹中的 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="PERSISTENCE_UNIT_T" transaction-type="JTA">
             <provider>foo.bar.PersistenceProvider</provider>
             <jta-data-source>jdbc/DB2</jta-data-source>
    
         </persistence-unit>
    
          <persistence-unit name="PERSISTENCE_UNIT_P" transaction-type="JTA">
             <provider>foo.bar.PersistenceProvider</provider>
             <jta-data-source>jdbc/DB2</jta-data-source>
    
         </persistence-unit> 
     </persistence>
    
  2. 限定符接口类SelectDataSource

 @Qualifier
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD })
    public @interface SelectDataSource{}
  1. EntityManager 类

    公共类 EntityManager {

         public EntityManager() {
         }
    
         @Inject
         @SelectDataSource
         private EntityManager entityManager;
    
         // other entity manager methods
    
     }
    
  2. Entity Manager Provider 类提供基于上下文的持久化单元

    公共类 EntityManagerProvider {

         @PersistenceContext(unitName = "PERSISTENCE_UNIT_T")
         private EntityManager entityManagerT;
    
         @PersistenceContext(unitName = "PERSISTENCE_UNIT_P")
         private EntityManager entityManagerP;
    
    
         @Produces
         @SelectDataSource
         EntityManager createEntityManager(InjectionPoint injectionPoint) {
    
             if (System.ENV.equalsIgnoreCase("p")) {
                 if (entityManagerP != null) {
    
                     return entityManagerP;
                 }
             }
    
             return entityManagerT;
         }
    
     }
    

然后可以使用@Inject

将 EntityManager 类注入到您喜欢的任何地方

下面是一篇关于如何使用上下文依赖注入创建托管实体管理器的好文章 https://www.sitepoint.com/cdi-weld-inject-jpa-hibernate-entity-managers/#usingaproducermethod

【讨论】:

    猜你喜欢
    • 2011-06-10
    • 2017-05-19
    • 1970-01-01
    • 2015-02-14
    • 2016-01-30
    • 1970-01-01
    • 2016-01-19
    • 2012-11-21
    • 1970-01-01
    相关资源
    最近更新 更多