2

我试图找出集成 Hibernate 和 Spring Data JPA 的新机制。我按照https://www.baeldung.com/hibernate-5-spring上提供的示例进行操作,但无济于事。进一步的研究给我带来了Juergen Hoeller在 Github 上的一个问题,他说:

[...] 这涵盖了很多开始的基础:在 Hibernate 5.2 和 5.3 中,LocalSessionFactoryBean 和 HibernateTransactionManager 在许多场景中充当 LocalContainerEntityManagerFactoryBean 和 JpaTransactionManager 的 99% 兼容替代品,允许与 SessionFactory.getCurrentSession() 交互(还有 HibernateTemplate) 在同一本地事务中的 @PersistenceContext EntityManager 交互旁边 (#21454)。除此之外,这样的设置还提供了更强大的 Hibernate 集成(#21494、#20852)和更多的配置灵活性,不受 JPA 引导合同的限制。

LocalSessionFactoryBean类的相应 Javadoc说明:

从 Spring 5.1 开始,与 Hibernate 5.0/5.1 以及 5.2/5.3 兼容。使用 Hibernate 5.3 设置,LocalSessionFactoryBean 是 LocalContainerEntityManagerFactoryBean 的直接替代品,用于常见的 JPA 目的:特别是在 Hibernate 5.3 中,Hibernate SessionFactory 也将本机公开 JPA EntityManagerFactory 接口,并且 Hibernate BeanContainer 集成将开箱即用地注册。结合 HibernateTransactionManager,这自然允许在同一事务中混合 JPA 访问代码和本机 Hibernate 访问代码。

我使用 Spring Boot 2.1.2.RELEASE 实现了一个简单的示例项目。它提供了一个简单的配置(与上面的 Baeldung 示例相同)并连接到 PostgreSQL 数据库。此外,从理论上讲,它使用模型和存储库来处理数据。这些类看起来像这样:

DemoApplication.java

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication
{

    public static void main(String[] args)
    {
        SpringApplication.run(DemoApplication.class, args);
    }
}

基本配置.java

package com.example.demo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.repository.config.BootstrapMode;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import org.postgresql.Driver;
import java.util.Properties;

@Configuration
@EnableJpaRepositories
public class BasicConfig
{
    @Bean
    public LocalSessionFactoryBean sessionFactory()
    {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        sessionFactory.setPackagesToScan("com.example.demo");
        sessionFactory.setHibernateProperties(hibernateProperties());

        return sessionFactory;
    }

    @Bean
    public DataSource dataSource()
    {
        SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
        dataSource.setDriverClass(Driver.class);
        dataSource.setUrl("jdbc:postgresql://localhost:5432/backend");
        dataSource.setUsername("backend");
        dataSource.setPassword("backend");

        return dataSource;
    }

    @Bean
    public PlatformTransactionManager hibernateTransactionManager()
    {
        HibernateTransactionManager transactionManager
                = new HibernateTransactionManager();
        transactionManager.setSessionFactory(sessionFactory().getObject());
        return transactionManager;
    }

    private final Properties hibernateProperties()
    {
        Properties hibernateProperties = new Properties();
        hibernateProperties.setProperty(
                "hibernate.hbm2ddl.auto", "create-drop");
        hibernateProperties.setProperty(
                "hibernate.dialect", "org.hibernate.dialect.PostgreSQL95Dialect");

        return hibernateProperties;
    }
}

模型.java

package com.example.demo;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "model")
public class Model
{
    @Id
    @GeneratedValue
    @Column(name = "id", unique = true, nullable = false)
    private Long id;

    @Column(name = "name")
    private String name;
}

DemoRepository.java

package com.example.demo;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface DemoRepository extends JpaRepository<Model, Long>
{
}

一旦我添加了DemoRepository应用程序就不再启动,因为:

A component required a bean named 'entityManagerFactory' that could not be found.


Action:

Consider defining a bean named 'entityManagerFactory' in your configuration.

完整的错误信息:

Exception encountered during context initialization - cancelling refresh
attempt: org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'demoRepository': 
Cannot create inner bean '(inner bean)#6c5ca0b6' of type  [org.springframework.orm.jpa.SharedEntityManagerCreator]  
while setting bean property 'entityManager';  
nested exception is org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name '(inner bean)#6c5ca0b6': 
Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; 
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No bean named 'entityManagerFactory' available

我的印象是,SessionFactory现在正确实施并公开了,EntityManagerFactory但似乎并非如此。我很确定我的实现存在缺陷,并且来自 Baeldung 的示例实际上可以正常工作。我希望有人可以向我指出并帮助我理解我的错误。
提前感谢大家。

依赖项:

  • spring-data-jpa:2.1.4.RELEASE
  • 弹簧芯:5.1.4.RELEASE
  • spring-orm:5.1.4.RELEASE
  • 休眠核心:5.3.7.Final
  • 弹簧启动:2.1.2.RELEASE

gradle.build

buildscript {
    ext {
        springBootVersion = '2.1.2.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.postgresql:postgresql'
}
4

1 回答 1

0

经过反复试验,我们发现了配置有什么问题。以下(精简)配置有效:

@Configuration
@EnableJpaRepositories(
        basePackages = "com.example.repository",
        bootstrapMode = BootstrapMode.DEFERRED
)
@EnableTransactionManagement
@Profile({ "local", "dev", "prod" })
public class DatabaseConfig
{
    @Bean
    public LocalSessionFactoryBean entityFactoryBean(
            final DataSource dataSource
    )
    {
        final LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();

        sessionFactory.setDataSource(dataSource);
        sessionFactory.setPackagesToScan("com.example.model");

        return sessionFactory;
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation()
    {
        return new PersistenceExceptionTranslationPostProcessor();
    }

    @Bean
    public HibernateTransactionManager transactionManager(
            final SessionFactory sessionFactory,
            final DataSource dataSource
    )
    {
        final HibernateTransactionManager transactionManager = new HibernateTransactionManager();

        transactionManager.setSessionFactory(sessionFactory);
        transactionManager.setDataSource(dataSource);

        return transactionManager;
    }
}

LocalSessionFactoryBean可以命名并且entityFactoryBeanSpring 仍然能够SessionFactoyhibernateTransactionManager. 如果其他人有类似的问题,我希望这会有所帮助。

于 2019-03-11T15:22:42.513 回答