【问题标题】:how to set EntityManagerFactory through constructor by @PersistenceUnit annotation如何通过 @PersistenceUnit 注释通过构造函数设置 EntityManagerFactory
【发布时间】:2013-07-29 06:25:16
【问题描述】:

有谁知道如何通过 @PersistenceUnit 注释通过构造函数设置 EntityManagerFactory 。我可以通过xml配置来做到这一点。但是不知道对应的注解配置。

<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jpaVendorAdapter">
  <bean
    class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml" />
<property name="persistenceUnitName" value="myUnit"></property>

<bean id="handler" class="com.handler.LocalHTHandler">
<constructor-arg ref="entityManagerFactory"></constructor-arg>

而且它工作正常。我们可以通过我的处理程序 bean 的注释来做到这一点吗?我听说过 @persistanceunit ,但它不能放在构造函数中来实现它。那是对的吗?

【问题讨论】:

    标签: spring jpa annotations


    【解决方案1】:

    正如@Dherik 所说,您可以通过构造函数执行此操作。多数据源示例如下(在SpringBoot 2.0.4上测试):

    SomeRepository.java

    @Repository
    public class SomeRepository {
    
        private final EntityManager entityManager;
    
        public TestService(@Qualifier("someEntityManagerFactory") EntityManager entityManager) {
            this.entityManager = entityManager;
        }
    }
    

    SomeDatabaseConfig.java

    import com.zaxxer.hikari.HikariDataSource;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
    import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
    import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
    import org.springframework.orm.jpa.JpaTransactionManager;
    import org.springframework.orm.jpa.JpaVendorAdapter;
    import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
    import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
    import org.springframework.orm.jpa.vendor.HibernateJpaDialect;
    import org.springframework.transaction.PlatformTransactionManager;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    import javax.persistence.EntityManagerFactory;
    import javax.sql.DataSource;
    
    @Configuration
    @EnableTransactionManagement
    @EnableJpaRepositories(entityManagerFactoryRef = "someEntityManagerFactory")
    @EnableConfigurationProperties(JpaProperties.class)
    class SomeDatabaseConfig {
    
        private static final String PERSISTENCE_UNIT = "some";
        private static final String[] PACKAGES_TO_SCAN = {"package.where.you.store.your.entities"};
    
        @Bean(name = "someDataSourceProps")
        @ConfigurationProperties("some.datasource")
        DataSourceProperties dataSourceProperties() {
            return new DataSourceProperties();
        }
    
        @Bean(name = "someDataSource")
        DataSource dataSource(@Qualifier("someDataSourceProps") DataSourceProperties properties) {
            return properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
        }
    
        @Bean(name = "someEntityManagerFactory")
        LocalContainerEntityManagerFactoryBean entityManagerFactory(
                JpaProperties jpaProperties,
                @Qualifier("someDataSource") DataSource dataSource,
                @Qualifier("someJpaVendorAdapter") JpaVendorAdapter jpaVendorAdapter) {
            return createEntityManagerFactory(jpaProperties, dataSource, jpaVendorAdapter, PERSISTENCE_UNIT, PACKAGES_TO_SCAN);
        }
    
        @Bean("someJpaVendorAdapter")
        JpaVendorAdapter jpaVendorAdapter(JpaProperties jpaProperties) {
            final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
            vendorAdapter.setShowSql(jpaProperties.isShowSql());
            return vendorAdapter;
        }
    
        @Bean(name = "someTransactionManager")
        PlatformTransactionManager transactionManager(@Qualifier("someEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
            return new JpaTransactionManager(entityManagerFactory);
        }
    
        static LocalContainerEntityManagerFactoryBean createEntityManagerFactory(JpaProperties jpaProperties, DataSource dataSource, JpaVendorAdapter jpaVendorAdapter, String persistenceUnit, String[] packagesToScan) {
            final LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
            factoryBean.setDataSource(dataSource);
            factoryBean.setJpaVendorAdapter(jpaVendorAdapter);
            factoryBean.setJpaDialect(new HibernateJpaDialect());
            factoryBean.setJpaPropertyMap(getVendorProperties(jpaProperties));
            factoryBean.setPersistenceUnitName(persistenceUnit);
            factoryBean.setPackagesToScan(packagesToScan);
            return factoryBean;
        }
    
        private static Map<String, Object> getVendorProperties(JpaProperties jpaProperties) {
            return jpaProperties.getHibernateProperties(new HibernateSettings());
        }
    }
    

    Application.java

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
    import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
    import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
    import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration;
    
    @SpringBootApplication(
            exclude = {
                    DataSourceAutoConfiguration.class,
                    HibernateJpaAutoConfiguration.class,
                    DataSourceTransactionManagerAutoConfiguration.class
            }
    )
    public class Application {
    
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    }
    

    【讨论】:

      【解决方案2】:

      目前,Spring team says 可以通过构造函数注入 EntityManager,因为它们已经在 Spring JPA 存储库中使用。

      只是:

      private final EntityManager em;
      
      public YourRepository(EntityManager em) {
          this.em = em;
      }
      

      我测试过。作品:)。不再有现场注入。

      【讨论】:

      【解决方案3】:

      Spring 无法使用 JSR 330 注释。目前不可能将 EntityManagers 注入构造函数,因为 @PersistenceContext 被定义为不允许在参数上使用。请参阅JPA_SPEC-72Allow injecting EntityManagers through constructor injection (and at non-@PersistenceContext injection points in general) [SPR-10443]

      【讨论】:

      • 嗨,Jarek。我赞成这个答案,因为它是我在构造函数问题上看到的最具体的事情。该链接现在已失效..如果您可以考虑寻找更新的参考资料,我们将不胜感激。谢谢。
      【解决方案4】:

      如果您出于某种原因不想在项目中使用 Spring Data(例如,您只是让遗留项目变得更好一点),您可以创建以下 FactoryBean 以通过构造函数注入使 EntityManager 可注入:

      /**
       * Makes the {@link EntityManager} injectable via <i>@Autowired</i>,
       * so it can be injected with constructor injection too.
       * (<i>@PersistenceContext</i> cannot be used for constructor injection.)
       */
      public static class EntityManagerInjectionFactory extends AbstractFactoryBean<EntityManager> {
      
          @PersistenceContext
          private EntityManager entityManager;
      
          @Override
          public Class<?> getObjectType() {
              return EntityManager.class;
          }
      
          @Override
          protected EntityManager createInstance() {
              return entityManager;
          }
      
      }
      

      请注意,因为我们在内部使用了@PersistenceContext 注解,所以返回的EntityManager 将是一个适当的线程安全代理,因为它会通过字段注入直接在使用位置注入。

      【讨论】:

        【解决方案5】:

        在我们的代码中,我们有一个基础 dao 对象,它通过 PersistenceContext 使用注入的实体管理器:

        public abstract class BasicJpaDao<T> implements IBasicDao<T> {
        
            @PersistenceContext(type = PersistenceContextType.TRANSACTION, unitName = "default")
            protected EntityManager entityManager;
        
            // Default constructor for Spring
            public BasicJpaDao() {}
        
            //Use this constructor to set the entity manager yourself
            public BasicJpaDao(EntityManager entityManager) {
                this.entityManager = entityManager;
            }
        
            ...
        
        }
        

        持久化单元在 Application Context 文件中定义如下:

        <!-- JPA -->
        <!-- Creates an EntityManagerFactory for use with the Hibernate JPA provider -->
        <bean id="entityManagerFactory"
            class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
            <property name="dataSource" ref="dataSourceGlobal" />
            <property name="packagesToScan" value="me.comocomo.nutrino.domain.jpa" />
            <property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
        
            <property name="jpaPropertyMap">
                <map merge="true">
                    <entry key="hibernate.format_sql" value="${hibernate.format_sql}" />
                </map>
            </property>
        </bean>
        
        <!-- jpaVendorAdapter (works in conjunction with the persistence.xml) -->
        <bean id="jpaVendorAdapter"
            class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="database" value="${jpa.database}" />
            <property name="showSql" value="${jpa.showSql}" />
            <property name="databasePlatform" value="${jpa.dialect}" />
            <property name="generateDdl" value="${jpa.generateDdl}" />
        </bean>
        
        <!-- In order to enable EntityManager injection -->
        <bean id="persistenceAnnotation"
            class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
        
        <!-- Transactions -->
        <tx:annotation-driven transaction-manager="transactionManager" />
        
        <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
            <property name="entityManagerFactory" ref="entityManagerFactory" />
            <property name="dataSource" ref="dataSourceGlobal" />
        </bean>
        

        同样,您可以创建一个 EntityManagerFactoryFactory 类,该类使用 Injection 获取 EntityManagerFactory,然后将工厂传递给您的 bean:

        @Component
        public class EntityManagerFactoryFactory {
        
            @Inject
            private EntityManagerFactory factory;
        }
        

        【讨论】:

        • 注入 entitymanger 很好。但我需要将 entitymanager 本身作为构造函数参数传递给 mybean。
        • 您可以添加一个默认构造函数供 Spring 在注入 EntityManager 时使用,以及另一个供您使用,例如在编辑中。然后,您可以将实体管理器注入您自己的 EntityManagerFactory 类,并将实体管理器传递给您的 bean。如果这不是您要查找的内容,请详细说明为什么需要在 bean 中手动设置实体管理器。
        • 在上面的评论中我犯了一个错误:我需要将 entitymanager 而是 entitymanagerfactory 作为构造函数参数传递给 mybean..
        • 我添加了另一个选项 - EntityManagerFactoryFactory。如果这是您需要的,请接受。 :)
        猜你喜欢
        • 1970-01-01
        • 2012-11-23
        • 1970-01-01
        • 2013-04-20
        • 2018-12-12
        • 1970-01-01
        • 2011-05-13
        • 1970-01-01
        相关资源
        最近更新 更多