【问题标题】:Import data at startup Spring boot启动时导入数据 Spring boot
【发布时间】:2021-02-12 20:20:20
【问题描述】:

我正在尝试在我的数据库初始化时启动一个 SQL 文件。

这是我的配置:

spring:
  profiles: local
  jpa:
    properties:
      hibernate.temp.use_jdbc_metadata_defaults: false
    generate-ddl: true
    hibernate:
      ddl-auto: update
    database: h2
    show-sql: true
    autoCommit: false
  datasource:
    platform: h2
    url: jdbc:h2:mem:db;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;
    driver-class-name: org.h2.Driver
    initialization-mode: always
    data: classpath:/sql/CreateGeographicZones.sql

我的脚本就是这一行(atm):

INSERT INTO GEOGRAPHIC_ZONE (name) VALUES ('EUROPE');

以及相关实体:

@NoArgsConstructor
@Data
@Entity
@Table(name = "GEOGRAPHIC_ZONE")
public class GeographicZone {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "geo_zone_sequence")
    @SequenceGenerator(name = "geo_zone_sequence", sequenceName = "geo_zone_id_seq", allocationSize = 1)
    @Column(nullable = false)
    private Long id;
    
   ...
}

正如我在日志中看到的那样,该表已创建: Hibernate: create table geographic_zone (id bigint not null, name varchar(100) not null, primary key (id))

但是我在执行脚本时出现了一个 SQL 错误:

Table "GEOGRAPHIC_ZONE" not found; SQL statement:
INSERT INTO GEOGRAPHIC_ZONE (name) VALUES ('EUROPE')

在日志中我可以看到我的表是在脚本执行之前创建的,为什么它不起作用?

【问题讨论】:

    标签: spring-boot hibernate spring-data-jpa


    【解决方案1】:

    根据您实体的元数据,Hibernate 正在查询geo_zone_id_seq 序列的下一个值并将其用于每次插入的 ID。

    如果您想在直接插入数据库时​​使用相同的方法,那么您需要实现 H2 Trigger

    您还可以使用EntityManager bean 或Spring JPA 存储库在应用程序启动后通过CommandLineRunner 接口插入数据。

    使用EntityManager

        @Bean
        CommandLineRunner registerZonesDataRunner(EntityManager entityManager, TransactionTemplate transactionTemplate) {
            return args -> transactionTemplate.execute(new TransactionCallbackWithoutResult() {
                @Override
                protected void doInTransactionWithoutResult(TransactionStatus status) {
                    // presuming that GeographicZone has a constructor expecting NAME 
                    Stream.of("AFRICA", "EUROPE")
                            .map(GeographicZone::new)
                            .forEach(entityManager::persist);
                }
            });
    

    使用 Spring JPA 存储库:

        @Bean
        CommandLineRunner registerZonesDataRunner(GeographicZoneRepository repository) {
                        // presuming that GeographicZone has a constructor expecting NAME 
            return args -> repository.saveAll(Stream.of("AFRICA", "EUROPE")
                    .map(GeographicZone::new)
                    .collector(Collectors.toList()));
        }
    

    minimal, reproducible example

    【讨论】:

      【解决方案2】:

      您没有显示如何定义 id 列,但架构表明没有自动生成方案。所以,试试:

      INSERT INTO GEOGRAPHIC_ZONE (id, name) VALUES (1, 'EUROPE');
      

      在您的数据文件中。如果可行,您需要在插入中手动设置id,或者将@GeneratedValue(strategy = AUTO) 之类的内容添加到@Id 属性中。

      【讨论】:

      • 我在班级中有一个带有@GeneratedValue 的 id,它与我的所有控制器都运行良好,只是脚本根本找不到我的表
      • 你的@GeneratedValue 策略是什么?
      • 我在我的问题中添加了它,但正如我之前所说的,当我通过我的 Rest 端点插入时它运行良好(也没有 id)
      • 使用 SEQUENCE,有一个单独的表(默认为 hibernate_sequence),它具有序列中的下一个。 Spring JPA 正在查询此表并在插入中使用 ID 的结果。如果要在不指定 ID 的情况下使用 SQL 插入,请使用 AUTO
      猜你喜欢
      • 2017-11-28
      • 2016-01-23
      • 2020-01-16
      • 1970-01-01
      • 2020-04-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-12
      相关资源
      最近更新 更多