【问题标题】:Relative persistence unit inject?相对持久化单元注入?
【发布时间】:2011-11-27 19:50:29
【问题描述】:

我有一个包含多个持久性单元定义文件的 Persistence.xml。

我要根据进入系统的用户注入单元EntityManager对象。

有可能吗?

@PersistenceContext (unitName = myUnit)

在这个使用中,我得到一个警告:“属性值必须是常数”

应用程序框架:JSF 2.1 和 Spring 3.0.2

持久层:JPA

【问题讨论】:

    标签: java jpa annotations


    【解决方案1】:

    您可以使用 CDI 吗?您可以编写一个注入所有不同上下文的小类,然后通过执行一些逻辑的生产者方法将它们提供给您的类。有点像这样:

    public class PersistenceContext {
        @PersistenceContext(unitName="myUnit") private EntityManager myEm;
        @PersistenceContext(unitName="yourUnit") private EntityManager yourEm;
    
        @Produces
        public EntityManager getEntityManager(InjectionPoint ip) {
            if (USER IS ME) {
                return myEm;
            }
            else if (USER IS YOU) {
                return yourEm;
            }
            else {
                NOW PANIC AND FREAK OUT
            }
        }
    }
    

    然后你可以像这样编写类:

    public class FeedReamer {
        @Inject private EntityManager em;
    }
    

    一切都会神奇地正确发生(可能?)。

    如果您不想硬编码类中持久性单元的名称,那么您可以显式获取实体管理器工厂,而不是依赖注入:

        @Produces
        public EntityManager getEntityManager(InjectionPoint ip) {
            String persistenceUnitName = somehowDeterminePersistenceUnitName();
            EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnitName);
            return emf.createEntityManager();
        }
    

    但是,尽管此方法可以在 J2SE 应用程序中工作,但不能保证 Persistence.createEntityManagerFactory 在 J2EE 中工作。规范中的脚注 42(至少是 EJB 3.0 持久性规范)说:

    Java EE 容器可能支持使用这些 Java SE 引导 API;但是,不需要支持此类使用。

    另外,我相信创建一个新的 EntityManagerFactory 会很慢;您可能会发现需要缓存查找结果。我相信长时间持有 EntityManagerFactory 并从多个线程访问它应该是安全的(但我不确定)。

    【讨论】:

    • 我认为这是正确的方向。不过,我不确定 Spring 是否没有自己实现 @Inject 和其他注释。想知道它将如何合作......
    • 啊,我错过了你在使用 Spring,对不起。我确信 Spring 有它自己的 @Produces 等价物——你应该能够使用它来实现相同的模式。
    • 嗨汤姆安德森。建议的方法,当有固定数量的单位可用时。单元数在我的系统上不稳定,可以随时增加,不想干扰java。
    • 您需要对代码进行的更改非常小;我建议你这样做。但是,我添加了一个建议,说明如何在不硬编码所有持久性单元名称的情况下做到这一点。
    【解决方案2】:

    正如错误消息所说,Java 注释属性必须是常量值,而不是对变量的引用。这是 Java 语言的限制,而不是 JPA。你需要找到一种不同的方式来做你想做的事情。

    【讨论】:

    • 最终变量无法解决这个问题。你能建议我找到一个不同的吗?
    • 我想说 private String unit = "myUnit";私有最终字符串 unitNanme = unit; @PersistenceContext(unitName=unitNanme) private EntityManager em;
    • 是的,我知道你在尝试什么;这是不允许的。
    【解决方案3】:

    正如在另一篇文章中提到的,注释属性必须是常量。

    另一种方法可能是以编程方式获取 EntityManager 实例:

    Persistence.getEntityManagerFactory().getEntityManager(persistenceUnitName);
    

    您可以根据自己的标准实现分配持久性单元名称所需的逻辑。显然,这具有与容器不再管理持久性相关的所有缺点。

    【讨论】:

    • 谢谢。显然,我想将持久性上下文留在关系春天。
    • 那么你想在运行时定义你想使用什么 PersistenceContext 并让 Spring 解决它?
    • Piotr Nowicki,我想在运行时定义 PersistenceContext 并使用并让 Spring 解决它。
    • 这段代码不太正确 - 持久性单元名称是 getEntityManagerFactory 的参数,而不是 getEntityManager。另外,我刚刚看到您提出了这个建议;我已经添加了与我的答案类似的内容。不抄袭,老实说!
    【解决方案4】:

    我找到了解决方案。我是春天的新手。肯定有更好的解决方案,但我仍然想分享解决方案。

    applicationContext.xml

    <context:component-scan base-package="com.hakdogan.hakdoganjsfspring"/ 
    
    <tx:annotation-driven transaction-manager="transactionManagerConstant"/ 
    
    <tx:annotation-driven transaction-manager="transactionManagerRelative"/ 
    
    <bean id="odev" class="com.hakdogan.hakdoganjsfspring.entity.Nesne"  / 
    
    <bean id="transactionManagerConstant" 
    class="org.springframework.orm.jpa.JpaTransactionManager"> 
        <property name="entityManagerFactory" ref="constant"/> 
        <property name="jpaDialect" ref="jpaDialect" /> 
    </bean> 
    <bean id="transactionManagerRelative" 
    class="org.springframework.orm.jpa.JpaTransactionManager"> 
        <property name="entityManagerFactory" ref="relative"/> 
        <property name="jpaDialect" ref="jpaDialect" /> 
    </bean> 
    <bean id="jpaDialect" 
    class="com.hakdogan.hakdoganjsfspring.util.HibernateExtendedJpaDialect" / 
    
    <bean id="persistenceUnitManager" 
    class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitMa nager"> 
    <property name="persistenceXmlLocations"> 
      <list> 
          <value>classpath*:META-INF/persistence.xml</value> 
          <value>classpath*:META-INF/hk.xml</value> 
      </list> 
    </property> 
    </bean> 
    <bean id="constant" 
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="persistenceUnitManager" 
    ref="persistenceUnitManager" /> 
    <property name="persistenceUnitName" value="JSFSpring" /> 
    </bean> 
    <bean id="relative" 
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="persistenceUnitManager" 
    ref="persistenceUnitManager" /> 
    </bean> 
    <bean id="persistenceManager" 
    class="com.hakdogan.hakdoganjsfspring.util.PersistenceManager"/> 
    </beans>
    

    PersistenceManager.java

    public class PersistenceManager { 
       private LocalContainerEntityManagerFactoryBean persistence; 
       public LocalContainerEntityManagerFactoryBean getPersistence() { 
        return persistence; 
       } 
    
       @Autowired 
       @Qualifier("relative") 
       public void setPersistence(LocalContainerEntityManagerFactoryBean 
    persistence) { 
        this.persistence = persistence; 
       } 
    }
    

    PersistDAO.java

    @Component("persistDAO") 
    @Scope("session") 
    public class PersistDAO { 
       @PersistenceContext(unitName="JSFSpring") 
       private EntityManager em; 
    
       @Autowired 
       private PersistenceManager persistenceManager; 
    
       @Autowired 
       private Nesne nesne; 
    
       private List<Odev> kayitListesi; 
       private List<Event> eventListesi; 
       private String myUnit = "hakdogan"; 
    
       public Nesne getNesne() { 
         return nesne; 
       } 
    
       public void setNesne(Nesne nesne) { 
         this.nesne = nesne; 
       } 
    
       @Transactional(isolation = Isolation.SERIALIZABLE, propagation = 
        Propagation.REQUIRED) 
       public String kaydet(){ 
          em.persist(nesne); 
          return "/liste.xhtml"; 
       } 
    
       @Transactional(propagation = Propagation.REQUIRED, readOnly=true) 
       public List<Odev> getKayitListesi() { 
          return kayitListesi = (List<Odev>) 
          em.createNamedQuery("Odev.findAll").getResultList(); 
       } 
    
       @Transactional(readOnly=true) 
       public List<Event> getEventListesi() { 
          persistenceManager.getPersistence().setPersistenceUnitName(myUnit); 
          EntityManager emt =        persistenceManager.getPersistence().getNativeEntityManagerFactory().createEntityManager(); 
        return eventListesi = (List<Event>) 
        emt.createNamedQuery("Event.findAll").getResultList(); 
       } 
    } 
    

    【讨论】:

      【解决方案5】:

      我的解决方案不是解决方案:)

      applicationContext.xml:

      <context:component-scan base-package="com.hakdogan.hakdoganjsfspring"/>
      <context:annotation-config />
      <tx:annotation-driven transaction-manager="transactionManagerConstant"/>
      <tx:annotation-driven transaction-manager="transactionManagerRelative"/>
      
      <bean id="jpaDialect" class="com.hakdogan.hakdoganjsfspring.util.HibernateExtendedJpaDialect" />
      <bean id="transactionManagerConstant" class="org.springframework.orm.jpa.JpaTransactionManager">
          <property name="entityManagerFactory" ref="constant"/>
          <property name="jpaDialect" ref="jpaDialect" />
      </bean>
      
      <bean id="transactionManagerRelative" class="org.springframework.orm.jpa.JpaTransactionManager">
          <property name="entityManagerFactory" ref="relative"/>
          <property name="jpaDialect" ref="jpaDialect" />
      </bean>
      
      <bean id="constant" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
         <property name="persistenceUnitManager" ref="persistenceUnitManager" />
         <property name="persistenceUnitName" value="JSFSpring" />
      </bean>
      
      <bean id="relative" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
         <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
         <property name="persistenceUnitName" value="hakdogan" />
      </bean>
      
      <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
         <property name="database" value="MYSQL"/>
         <property name="showSql" value="true"/>
         <property name="generateDdl" value="false"/>
         <property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
      </bean>
      
      <bean id="persistenceUnitManager" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
        <property name="persistenceXmlLocations">
         <list>
            <value>classpath*:META-INF/persistence.xml</value>
         </list>
        </property>
      </bean>
      
      <bean id="persistenceManager" class="com.hakdogan.hakdoganjsfspring.util.PersistenceManager"/>
      <bean id="odev" class="com.hakdogan.hakdoganjsfspring.entity.Odev" scope="prototype" />
      
      </beans>
      

      PersistenceManager.java:

      public class PersistenceManager {
      
      
      @Autowired
      private LocalEntityManagerFactoryBean persistence;
      private PersistenceProvider provider;
      
       public EntityManager getBaglam(String unitName){
          if(null == provider)
              provider = persistence.getPersistenceProvider();
      
          if(!unitName.equals(persistence.getPersistenceUnitName()))
              persistence.setPersistenceUnitName(unitName);
      
          return provider.createEntityManagerFactory(unitName, null).createEntityManager();
       }
      }
      

      PersistDAO.java:

      @Component("persistDAO")
      @Scope("session")
      public class PersistDAO {
      
         @PersistenceContext(unitName="JSFSpring")
         private EntityManager em;
      
      
      @Autowired
      private PersistenceManager persistenceManager;
      
      private List<Odev> kayitListesi;
      private List<Event> eventListesi;
      private List<Musteriler> musteriListesi;    
      
      private String myUnit = "hakdogan";
      
      
      @Transactional(propagation = Propagation.REQUIRED, readOnly=true)
      public List<Odev> getKayitListesi() {
          return kayitListesi = (List<Odev>) em.createNamedQuery("Odev.findAll").getResultList();
      }
      
      @Transactional(isolation = Isolation.SERIALIZABLE, propagation = Propagation.REQUIRED)
      public List<Event> getEventListesi() {
          return persistenceManager.getBaglam(myUnit).createQuery("SELECT e FROM Event e").getResultList();
      }
      
      @Transactional(isolation = Isolation.SERIALIZABLE, propagation = Propagation.REQUIRED)
      public List<Musteriler> getMusteriListesi() {
          return persistenceManager.getBaglam("musteri").createNamedQuery("Musteriler.findAll").getResultList();
      }
      }
      

      没有 LocalEntityManagerFactoryBean persistenceUnitManager 等属性。由于这个原因,我无法设置单位的名称。

      成本是在发生时创建 EntityManagerFactory。试图减慢项目的速度。

      我正在寻找春季有效的解决方案。

      谢谢。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-05-03
        • 2017-02-17
        • 2018-10-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多