【问题标题】:Spring boot - configure EntityManagerSpring Boot - 配置 EntityManager
【发布时间】:2016-01-09 13:03:18
【问题描述】:

我在我的项目中使用Google guice,现在我尝试将框架完全转换为SpringBoot

我为persistence.xml 配置了 Bean,就像 below in

@Autowired
@Bean(name = "transactionManager")
public LocalContainerEntityManagerFactoryBean entityManagerFactory()
{
    LocalContainerEntityManagerFactoryBean lEMF =  new LocalContainerEntityManagerFactoryBean();
    lEMF.setPersistenceUnitName("leaseManagementPU");
    lEMF.setPersistenceXmlLocation("persistence.xml");
    return lEMF;
}

现在我需要配置(注入)EntityManager em,执行 JPA operations 之类的 em.persist()em.find 等...我该如何配置,也有人尝试用示例代码解释这一点

【问题讨论】:

    标签: spring-boot


    【解决方案1】:

    使用Spring Boot 不需要像persistence.xml 这样的配置文件。您可以使用annotations 进行配置,只需在

    中为 JPA 配置数据库配置即可

    application.properties

    spring.datasource.driverClassName=oracle.jdbc.driver.OracleDriver
    spring.datasource.url=jdbc:oracle:thin:@DB...
    spring.datasource.username=username
    spring.datasource.password=pass
    
    spring.jpa.database-platform=org.hibernate.dialect....
    spring.jpa.show-sql=true
    

    然后您可以使用 Spring 提供的 CrudRepository,您可以使用标准的 CRUD 事务方法。在那里你也可以实现你自己的SQL's,比如JPQL

    @Transactional
    public interface ObjectRepository extends CrudRepository<Object, Long> {
    ...
    }
    

    如果您仍然需要使用Entity Manager,您可以创建另一个类。

    public class ObjectRepositoryImpl implements ObjectCustomMethods{
    
        @PersistenceContext
        private EntityManager em;
    
    }
    

    这应该在你的pom.xml

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.5.RELEASE</version>
    </parent>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>4.3.11.Final</version>
        </dependency>
    </dependencies>
    

    【讨论】:

    • 谢谢,是否可以使用 JPARepository 代替 CRUD 存储库。有什么区别
    • 我认为这应该不是问题。 Here 是一个很好的文档。
    • @Patrick 如果有自定义数据源连接到不同的数据库怎么办。在那种情况下,您不需要使用单独的 entitymanagers 吗?在这种情况下如何传递休眠属性?
    • 我正在努力将 EntityManager 传递到 SpringBtach 的 Tasklet 的问题
    【解决方案2】:

    嗯,你可以找到很多配置 spring 框架的示例。无论如何,这里是一个示例

    @Configuration
    @Import({PersistenceConfig.class})
    @ComponentScan(basePackageClasses = { 
        ServiceMarker.class,
        RepositoryMarker.class }
    )
    public class AppConfig {
    
    }
    

    持久化配置

    @Configuration
    @PropertySource(value = { "classpath:database/jdbc.properties" })
    @EnableTransactionManagement
    public class PersistenceConfig {
    
        private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
        private static final String PROPERTY_NAME_HIBERNATE_MAX_FETCH_DEPTH = "hibernate.max_fetch_depth";
        private static final String PROPERTY_NAME_HIBERNATE_JDBC_FETCH_SIZE = "hibernate.jdbc.fetch_size";
        private static final String PROPERTY_NAME_HIBERNATE_JDBC_BATCH_SIZE = "hibernate.jdbc.batch_size";
        private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
        private static final String[] ENTITYMANAGER_PACKAGES_TO_SCAN = {"a.b.c.entities", "a.b.c.converters"};
    
        @Autowired
        private Environment env;
    
         @Bean(destroyMethod = "close")
         public DataSource dataSource() {
             BasicDataSource dataSource = new BasicDataSource();
             dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
             dataSource.setUrl(env.getProperty("jdbc.url"));
             dataSource.setUsername(env.getProperty("jdbc.username"));
             dataSource.setPassword(env.getProperty("jdbc.password"));
             return dataSource;
         }
    
         @Bean
         public JpaTransactionManager jpaTransactionManager() {
             JpaTransactionManager transactionManager = new JpaTransactionManager();
             transactionManager.setEntityManagerFactory(entityManagerFactoryBean().getObject());
             return transactionManager;
         }
    
        private HibernateJpaVendorAdapter vendorAdaptor() {
             HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
             vendorAdapter.setShowSql(true);
             return vendorAdapter;
        }
    
        @Bean
        public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
    
             LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
             entityManagerFactoryBean.setJpaVendorAdapter(vendorAdaptor());
             entityManagerFactoryBean.setDataSource(dataSource());
             entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
             entityManagerFactoryBean.setPackagesToScan(ENTITYMANAGER_PACKAGES_TO_SCAN);             
             entityManagerFactoryBean.setJpaProperties(jpaHibernateProperties());
    
             return entityManagerFactoryBean;
         }
    
         private Properties jpaHibernateProperties() {
    
             Properties properties = new Properties();
    
             properties.put(PROPERTY_NAME_HIBERNATE_MAX_FETCH_DEPTH, env.getProperty(PROPERTY_NAME_HIBERNATE_MAX_FETCH_DEPTH));
             properties.put(PROPERTY_NAME_HIBERNATE_JDBC_FETCH_SIZE, env.getProperty(PROPERTY_NAME_HIBERNATE_JDBC_FETCH_SIZE));
             properties.put(PROPERTY_NAME_HIBERNATE_JDBC_BATCH_SIZE, env.getProperty(PROPERTY_NAME_HIBERNATE_JDBC_BATCH_SIZE));
             properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
    
             properties.put(AvailableSettings.SCHEMA_GEN_DATABASE_ACTION, "none");
             properties.put(AvailableSettings.USE_CLASS_ENHANCER, "false");      
             return properties;       
         }
    
    }
    

    主要

    public static void main(String[] args) { 
        try (GenericApplicationContext springContext = new AnnotationConfigApplicationContext(AppConfig.class)) {
            MyService myService = springContext.getBean(MyServiceImpl.class);
            try {
                myService.handleProcess(fromDate, toDate);
            } catch (Exception e) {
                logger.error("Exception occurs", e);
                myService.handleException(fromDate, toDate, e);
            }
        } catch (Exception e) {
            logger.error("Exception occurs in loading Spring context: ", e);
        }
    }
    

    我的服务

    @Service
    public class MyServiceImpl implements MyService {
    
        @Inject
        private MyDao myDao;
    
        @Override
        public void handleProcess(String fromDate, String toDate) {
            List<Student> myList = myDao.select(fromDate, toDate);
        }
    }
    

    MyDaoImpl

    @Repository
    @Transactional
    public class MyDaoImpl implements MyDao {
    
        @PersistenceContext
        private EntityManager entityManager;
    
        public Student select(String fromDate, String toDate){
    
            TypedQuery<Student> query = entityManager.createNamedQuery("Student.findByKey", Student.class);
            query.setParameter("fromDate", fromDate);
            query.setParameter("toDate", toDate);
            List<Student> list = query.getResultList();
            return CollectionUtils.isEmpty(list) ? null : list;
        }
    
    }
    

    假设 maven 项目: 属性文件应该在src/main/resources/database 文件夹中

    jdbc.properties 文件

    jdbc.driverClassName=com.mysql.jdbc.Driver
    jdbc.url=your db url
    jdbc.username=your Username
    jdbc.password=Your password
    
    hibernate.max_fetch_depth = 3
    hibernate.jdbc.fetch_size = 50
    hibernate.jdbc.batch_size = 10
    hibernate.show_sql = true
    

    ServiceMarker 和 RepositoryMarker 只是您的服务或存储库 impl 包中的空接口。

    假设你有包名a.b.c.service.impl。 MyServiceImpl 和 ServiceMarker 都在这个包中。

    public interface ServiceMarker {
    
    }
    

    存储库标记也是如此。假设您有 a.b.c.repository.impla.b.c.dao.impl 包名称。那么MyDaoImpl就在这个这个包里,也是Repositorymarker

    public interface RepositoryMarker {
    
    }
    

    a.b.c.entities.Student

    //dummy class and dummy query
    @Entity
    @NamedQueries({
    @NamedQuery(name="Student.findByKey", query="select s from Student s where s.fromDate=:fromDate" and s.toDate = :toDate)
    })
    public class Student implements Serializable {
    
        private LocalDateTime fromDate;
        private LocalDateTime toDate;
    
        //getters setters
    
    }
    

    a.b.c.转换器

    @Converter(autoApply = true)
    public class LocalDateTimeConverter implements AttributeConverter<LocalDateTime, Timestamp> {
    
        @Override
        public Timestamp convertToDatabaseColumn(LocalDateTime dateTime) {
    
            if (dateTime == null) {
                return null;
            }
            return Timestamp.valueOf(dateTime);
        }
    
        @Override
        public LocalDateTime convertToEntityAttribute(Timestamp timestamp) {
    
            if (timestamp == null) {
                return null;
            }    
            return timestamp.toLocalDateTime();
        }
    }
    

    pom.xml

    <properties>
        <java-version>1.8</java-version>
        <org.springframework-version>4.2.1.RELEASE</org.springframework-version>
        <hibernate-entitymanager.version>5.0.2.Final</hibernate-entitymanager.version>
        <commons-dbcp2.version>2.1.1</commons-dbcp2.version>
        <mysql-connector-java.version>5.1.36</mysql-connector-java.version>
         <junit.version>4.12</junit.version> 
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
    
        <!-- Spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
    
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
    
        <dependency>
            <groupId>javax.inject</groupId>
            <artifactId>javax.inject</artifactId>
            <version>1</version>
            <scope>compile</scope>
        </dependency>
    
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${org.springframework-version}</version>
        </dependency>
    
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${org.springframework-version}</version>
        </dependency>
    
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${hibernate-entitymanager.version}</version>
        </dependency>
    
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql-connector-java.version}</version>
        </dependency>
    
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-dbcp2</artifactId>
            <version>${commons-dbcp2.version}</version>
        </dependency>
    </dependencies>
    
    <build>
         <finalName>${project.artifactId}</finalName>
         <plugins>
             <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <source>${java-version}</source>
                    <target>${java-version}</target>
                    <compilerArgument>-Xlint:all</compilerArgument>
                    <showWarnings>true</showWarnings>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>
         </plugins>
    </build>
    

    希望对您有所帮助。谢谢

    【讨论】:

    • 我的荣幸 :) 你也可以在你的项目中使用 Spring Data JPA。通过这种方式,您不必在域类上编写简单的查询。它还将进一步简化您的应用程序。关注此链接docs.spring.io/spring-data/jpa/docs/current/reference/html/…
    • 太好了 - 最后是一些关于如何做到这一点的文档!只有一个问题,我现在将解决这个问题,因为它很清楚如何做到这一点:如何在不依赖 JDBC 驱动程序类和连接池类的硬编码依赖的情况下对其进行编码?
    • 在 POM 中有 MySQLmysql-connector-java 的依赖。这可能是 SQLServer 或 oracle。但是对于 SQLServer 或 Oracle 或任何专有的 JDBC 驱动程序,您需要下载 jar 并使用 maven 将其导入 maven 本地存储库。你可以谷歌。这很容易。也用于连接池在 POM 中有commons-dbcp2。在PersistenceConfig 参见dataSource()。我使用了默认值。但是你可以根据自己的需要进行配置。就像我在网上说的很多教程一样;) :)
    • 也从休眠 5.2.0 开始。 hibernate-entitymanager 不再需要。只需包括hibernate-core。但是 5.2.0 在进程收集时 Spring Data JPA 有问题。如果您使用 Spring Data JPA,则 hibernate-core 5.2.1 及更高版本可以使用 Spring Data JPA。
    • @Basit:感谢您提供的信息。快速提问:entityManager 引用如何填充,即使没有与此名称/类型关联的 bean?它是 Spring 在幕后实现的吗?是如何实现的?
    猜你喜欢
    • 2020-03-16
    • 1970-01-01
    • 2018-09-21
    • 2014-12-13
    • 2014-05-16
    • 2019-10-21
    • 2014-10-05
    • 2018-02-12
    • 2015-08-11
    相关资源
    最近更新 更多