【问题标题】:Spring/Hibernate multiple data sources with foreign key between themSpring/Hibernate 多个数据源之间具有外键
【发布时间】:2021-09-09 17:26:15
【问题描述】:

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

@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,它与crm 数据源(模式)中的实体Person 具有一对一的映射关系.

@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,因此生成两个彼此一无所知的实体列表。

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

谢谢。

【问题讨论】:

    标签: java spring spring-boot hibernate hibernate-mapping


    【解决方案1】:

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

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

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

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

    【讨论】:

      猜你喜欢
      • 2012-10-18
      • 2010-10-26
      • 1970-01-01
      • 2015-07-01
      • 2014-05-01
      • 2014-07-24
      • 2019-01-21
      • 2011-04-20
      • 2014-12-06
      相关资源
      最近更新 更多