我试图找出集成Hibernate和Spring Data JPA的新机制。我按照https://www.baeldung.com/hibernate-5-spring提供的例子,但无济于事。进一步的研究为我带来了Juergen Hoeller的issue on Github说:
[...]这包括很多开始:使用Hibernate 5.2和5.3,LocalSessionFactoryBean和HibernateTransactionManager在许多情况下充当LocalContainerEntityManagerFactoryBean和JpaTransactionManager的99%兼容替代品,允许与SessionFactory.getCurrentSession()进行交互(以及同一本地事务中的@PersistenceContext EntityManager交互旁边的HibernateTemplate(#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数据库。此外,它在理论上使用模型和存储库来处理数据。这些类看起来像这样:
demo application.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);
}
}
BASIC config.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;
}
}
model.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;
}
demo repository.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
,App就不再启动,因为:
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
now正确地实施并暴露了EntityManagerFactory
,但似乎并非如此。我很确定我的实现存在缺陷,并且Baeldung的示例实际上正常工作。我希望有人可以向我指出并帮助我理解我的错误。
感谢大家提前。
依赖关系:
grad了.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'
}
经过一些反复试验,我们发现配置有什么问题。以下(删节)配置有效:
@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
可以命名为entityFactoryBean
,而Spring仍然可以为SessionFactoy
自动装配hibernateTransactionManager
。我希望如果其他人有类似的问题,这会有所帮助。