【问题标题】:Spring Boot - multiple datasource - hbm2ddl issueSpring Boot - 多个数据源 - hbm2ddl 问题
【发布时间】:2020-01-15 22:54:24
【问题描述】:

我在我的 Spring Boot(版本 2.1.3.Final)应用程序中定义了多个数据源,对于其中一个,我将 hbm2ddl 设置为更新。但是,如果我第二次运行该应用程序,它总是会尝试执行 CREATE TABLE 语句(而不是 alter,或者在实体没有变化的情况下不执行语句)

数据源定义如下所示:

    // @formatter:off
@EnableJpaRepositories(entityManagerFactoryRef = "triggerEMF", transactionManagerRef = "triggerTM", basePackages = {
        "com.customer.trigger.repository" }, excludeFilters = @Filter(CDHRepository.class))
// @formatter:on
@Configuration
@EnableTransactionManagement
public class TriggerDSConfig {

    private static final Logger LOGGER = LoggerFactory.getLogger(TriggerDSConfig.class);

    @Autowired
    private Environment env;

    @Primary
    @Bean(name = "triggerDS")
    @ConfigurationProperties("trigger.datasource")
    public DataSource dataSource() {

        return DataSourceBuilder.create().build();

    }

    @Primary
    @Bean(name = "triggerTM")
    public PlatformTransactionManager psqlTransactionManager(@Qualifier("triggerEMF") EntityManagerFactory customerEntityManagerFactory) {
        return new JpaTransactionManager(customerEntityManagerFactory);

    }

    @Primary
    @Bean(name = "triggerEMF")
    public LocalContainerEntityManagerFactoryBean psqlEntityManager(EntityManagerFactoryBuilder builder) throws SQLException {
        Map<String, String> props = new HashMap<String, String>();
        props.put("hibernate.hbm2ddl.auto", env.getProperty("trigger.hbm2ddl"));
        props.put("hibernate.dialect", env.getProperty("trigger.dialect"));
        props.put("hibernate.default_schema", "public");

        DataSource ds = dataSource();
        ds.getConnection(); // eager connection pool init

        return builder.dataSource(ds) //
                .packages("com.customer.trigger.model.entity") //
                .persistenceUnit("trigger-pu") //
                .properties(props) //
                .build(); //

    }

    // Initialise & Populate DS in Local profile
    @Bean
    @Profile({ "local" })
    public DataSourceInitializer triggerEngineDBInit(@Qualifier("triggerDS") DataSource datasource) {

        ResourceDatabasePopulator resourceDatabasePopulator = new ResourceDatabasePopulator();
        resourceDatabasePopulator.addScript(new ClassPathResource("db/schema-triggerengine.sql"));
        resourceDatabasePopulator.addScript(new ClassPathResource("db/data-triggerengine.sql"));

        DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();
        dataSourceInitializer.setDataSource(datasource);
        dataSourceInitializer.setDatabasePopulator(resourceDatabasePopulator);
        dataSourceInitializer.setEnabled(env.getProperty("trigger.datasource.initialize", Boolean.class, false));
        return dataSourceInitializer;
    }

}

此数据源的 YAML 定义如下所示:

    trigger:
  datasource:
    jdbcUrl: jdbc:h2:~/triggerdb2;DB_CLOSE_ON_EXIT=FALSE;MODE=PostgreSQL
    username: sa
    password: sa
  hbm2ddl: update
  dialect: org.hibernate.dialect.H2Dialect

我可以确认没有执行 DDL 脚本。这是失败的 hbm2ddl。我对它进行了深入的调试,并且我已经掌握了这个类: https://github.com/hibernate/hibernate-orm/blob/master/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/GroupedSchemaMigratorImpl.java

这是有问题的一段代码: https://github.com/hibernate/hibernate-orm/blob/master/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/GroupedSchemaMigratorImpl.java#L69-L71

表信息为空——所以hibernate生成create table语句(而不是alter或no语句)。但当然该表存在,因此失败并出现以下错误:

            at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:67)
        at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.applySqlString(AbstractSchemaMigrator.java:559)
        at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.applySqlStrings(AbstractSchemaMigrator.java:504)
        at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.createTable(AbstractSchemaMigrator.java:277)
        at org.hibernate.tool.schema.internal.GroupedSchemaMigratorImpl.performTablesMigration(GroupedSchemaMigratorImpl.java:71)
        at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.performMigration(AbstractSchemaMigrator.java:207)
        at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.doMigration(AbstractSchemaMigrator.java:114)
        at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:183)
        at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:72)
        at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:310)
        at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:467)
        at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:939)
        at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:57)
        at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365)
        at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:390)
        at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:377)
        at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1821)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1758)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
        at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1105)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:316)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248)
        at com.customer.trigger.Application.main(Application.java:11)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run(AbstractRunMojo.java:558)
        at java.lang.Thread.run(Thread.java:748)
Caused by: org.h2.jdbc.JdbcSQLException: Table "SUGGESTION_VOD__C" already exists; SQL statement:

PostgreSQL 也会出现这个问题(不仅仅是 H2)

有什么想法吗?

复制者:

https://github.com/agiertli/spring-boot-hbm-ddl-issue

【问题讨论】:

  • 可以在github上创建一个测试用例吗?
  • 嗨,我在最初的帖子中添加了一个复制器的链接。包含自述文件。
  • 这可能是一个很长的镜头,但你能验证来自env.getProperty("trigger.hbm2ddl") 的值是update 吗?我敢肯定,但最好验证一下。
  • 嗨,我可以确认值是更新。当我将它打印到控制台时,这是可见的,而且,当我调试时,我能够看到 hibernate 正在尝试执行更新,但由于某种原因它看不到我们的表,所以它生成了 create-table 语句。跨度>

标签: java hibernate spring-boot datasource


【解决方案1】:

我在本地运行了您的项目。你是对的,当我跑了两次我得到表已经存在错误。解决方案是

Map<String, String> props = new HashMap<String, String>();
props.put("hibernate.hbm2ddl.auto", "update");
props.put("hibernate.dialect", env.getProperty("trigger.dialect"));
props.put("hibernate.default_schema", env.getProperty("trigger.schema"));

您可能在 yml.xml 中缺少某些属性。还要对这些属性使用 @Value。

【讨论】:

    【解决方案2】:

    删除以下 yaml 配置后:

           # temp:
            #  use_jdbc_metadata_defaults: "false"
    

    问题不再出现。当然,现在我们收到了与 CLOB 相关的奇怪错误,但它们似乎没有真正的影响,所以这是一个单独的问题。

    【讨论】:

      【解决方案3】:

      我读到了你的问题。问题不取决于数据库,我认为您的问题是您没有为您的项目使用数据库版本控制。 版本控制会为您处理所有这些事情(它知道何时创建或更改等等)。

      这些是您可以使用的很好的数据库版本控制 liquibase flyway

      我的意见是使用 liquibase,因为它有非常好的文档会更容易

      【讨论】:

        猜你喜欢
        • 2023-03-20
        • 2017-07-23
        • 1970-01-01
        • 2015-02-21
        • 1970-01-01
        • 1970-01-01
        • 2023-03-14
        • 1970-01-01
        • 2016-09-14
        相关资源
        最近更新 更多