首页 > 解决方案 > Spring/Hibernate 多个数据源之间具有外键

问题描述

假设我有两个表,在不同的模式中。因此,我为每个数据源创建了一个实体和事务管理器:

@Configuration
@EnableJpaRepositories(
    basePackages = "com.(omitted).endpoints.all.endpoint.crm",
    entityManagerFactoryRef = "crmEntityManager",
    transactionManagerRef = "crmTransactionManager"
)
public class PersistenceCrmConfig {

  @Autowired
  private Environment environment;

  public PersistenceCrmConfig() {
    super();
  }

  @Primary
  @Bean
  public LocalContainerEntityManagerFactoryBean crmEntityManager() {
    final LocalContainerEntityManagerFactoryBean bean = new LocalContainerEntityManagerFactoryBean();

    bean.setDataSource(crmDataSource());
    bean.setPackagesToScan("com.(omitted).data.all.model.crm");

    ...
  }

  @Primary
  @Bean
  public PlatformTransactionManager crmTransactionManager() {
    ...
  }

  @Primary
  @Bean
  public DataSource crmDataSource() {
    ...
  }

}
@Configuration
@EnableJpaRepositories(
    basePackages = "com.(omitted).endpoints.all.endpoint.user",
    entityManagerFactoryRef = "userEntityManager",
    transactionManagerRef = "userTransactionManager"
)
public class PersistenceUserConfig {

  @Autowired
  private Environment environment;

  public PersistenceUserConfig() {
    super();
  }

  @Primary
  @Bean
  public LocalContainerEntityManagerFactoryBean userEntityManager() {
    final LocalContainerEntityManagerFactoryBean bean = new LocalContainerEntityManagerFactoryBean();

    bean.setDataSource(userDataSource());
    bean.setPackagesToScan("com.(omitted).data.all.model.user");

    ...
  }

  @Primary
  @Bean
  public PlatformTransactionManager userTransactionManager() {
    ...
  }

  @Primary
  @Bean
  public DataSource userDataSource() {
    ...
  }

}

user数据源(模式)中,我有一个实体 ,它与数据源(模式)中的实体User有一对一的映射。Personcrm

@JoinColumn(name = "person_id", nullable = false)
@OneToOne(fetch = FetchType.LAZY)
private Person person;

这会导致异常:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userEntityManager' defined in class path resource [com/(omitted)/endpoints/all/spring/PersistenceUserConfig.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: @OneToOne or @ManyToOne on com.(omitted).data.all.model.user.User.person references an unknown entity: com.(omitted).data.all.model.crm.Person
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1786) ~[spring-beans-5.3.8.jar:5.3.8]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:602) ~[spring-beans-5.3.8.jar:5.3.8]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) ~[spring-beans-5.3.8.jar:5.3.8]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.8.jar:5.3.8]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.8.jar:5.3.8]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.8.jar:5.3.8]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.8.jar:5.3.8]
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1154) ~[spring-context-5.3.8.jar:5.3.8]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:908) ~[spring-context-5.3.8.jar:5.3.8]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.8.jar:5.3.8]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.5.1.jar:2.5.1]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-2.5.1.jar:2.5.1]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434) ~[spring-boot-2.5.1.jar:2.5.1]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:338) ~[spring-boot-2.5.1.jar:2.5.1]
    at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:144) ~[spring-boot-2.5.1.jar:2.5.1]
    at com.(omitted).endpoints.all.Application.main(Application.java:11) ~[classes/:na]
Caused by: org.hibernate.AnnotationException: @OneToOne or @ManyToOne on com.(omitted).data.all.model.user.User.person references an unknown entity: com.(omitted).data.all.model.crm.Person
    at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:100) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processEndOfQueue(InFlightMetadataCollectorImpl.java:1823) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processFkSecondPassesInOrder(InFlightMetadataCollectorImpl.java:1767) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1655) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:295) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1224) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1255) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:58) ~[spring-orm-5.3.8.jar:5.3.8]
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365) ~[spring-orm-5.3.8.jar:5.3.8]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409) ~[spring-orm-5.3.8.jar:5.3.8]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:396) ~[spring-orm-5.3.8.jar:5.3.8]
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341) ~[spring-orm-5.3.8.jar:5.3.8]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1845) ~[spring-beans-5.3.8.jar:5.3.8]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1782) ~[spring-beans-5.3.8.jar:5.3.8]
    ... 15 common frames omitted

我明白为什么我会收到这个错误。Spring 必须生成两个 Hibernate Session Factories,因此,两个彼此一无所知的实体列表。

如何使一对一映射起作用?

谢谢你。

标签: javaspringspring-boothibernatehibernate-mapping

解决方案


没有办法让它与两个 Hibernate Session Factories 一起工作。我也不建议尝试强制 Hibernate 为这种情况创建一个。

我看到的简单解决方法是在数据库方面。person考虑在user架构中创建表视图并将Person实体映射到视图,而不是表。

这种方法不允许您person使用您的更新表userEntityManager(除非您使用的是 Oracle DB)。如果您需要在某些时候执行此操作,您可以使用您在表crmEntityManager中找到相应person的并更新它。

请记住,如果由于您提到的相同原因(不同的会话工厂)而必须同时更新两者personuser作为单个操作的一部分进行更新,则事务性可能会受到损害。


推荐阅读