内存数据库H2中的Spring Boot在初始化时不会从文件中加载数据

Posted

技术标签:

【中文标题】内存数据库H2中的Spring Boot在初始化时不会从文件中加载数据【英文标题】:Spring Boot in memory database H2 doesn't load data from file on initialization 【发布时间】:2017-06-10 00:17:55 【问题描述】:

我在应用程序初始化时将数据加载到内存数据库时遇到问题。我创建了包含表结构和初始数据的 schema.sqldata.sql 文件。

schema.sql:

CREATE TABLE users (
  id          INT PRIMARY KEY,
  username    VARCHAR(64) NOT NULL,
  password    VARCHAR(64) 
);

data.sql

INSERT INTO users (id, username, password) VALUES
  (1, 'usr1', 'bigSecret'),
  (2, 'usr2', 'topSecret');

我正在使用JpaRepository 处理数据层:

public interface UserRepository extends JpaRepository<User, Long> 

而且我还配置了application.properties

spring.datasource.initialize=true
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=- 1;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

但是当我打电话时

List<User> users = userRepository.findAll();

用户实体

@Entity
@Table(name = "users")
public class User 

  @Id
  @GeneratedValue
  private Long id;
  private String username;
  private String password;

  public User()   

  public Long getId() 
    return id;
  

  public void setId(Long id) 
    this.id = id;
  

  public String getUsername() 
    return username;
  

  public void setUsername(String username) 
    this.username = username;
  

  public String getPassword() 
    return password;
  

  public void setPassword(String password) 
    this.password = password;
  

我得到一个空列表,但我应该从我的内存 H2 数据库中获取两个预先填充的用户。内存数据库有什么问题? 谢谢。

【问题讨论】:

你把这些脚本放在哪里了? 我想知道您的网址是否可以使用额外的空间DB_CLOSE_DELAY=- 1; => DB_CLOSE_DELAY=-1; 你能显示你的User实体吗 @Maciej Kowalski 我已将脚本放入 /src/main/resources 中,似乎它们已被应用程序读取。 @alexbt 我删除了空间并且结果相同 - 没有从文件中提取数据 【参考方案1】:

您始终可以尝试根据 h2 规范运行这些脚本,您应该在连接 url 中添加一个 INIT 脚本(作为选项之一):

jdbc:h2:mem:test;INIT=RUNSCRIPT FROM '~/schema.sql'\;RUNSCRIPT FROM '~/data.sql'"

此功能通过 INIT 属性启用。注意 可以将多个命令传递给 INIT,但分号分隔符 必须转义,如下例所示。

更新

请注意,在您的 application.properties 中有这些选项:

spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=true
spring.datasource.initialize=true

在启动过程中可能会导致一些冲突。因此,您应该始终瞄准其中一个,但绝不能同时瞄准两者。 对于简单的情况,仅这些就足以在关机和启动后自动构建表并重新加载

【讨论】:

我已尝试将 sql 脚本(schema.sql 和 data.sql)添加到 application.conf 的 spring.datasource.url 属性中的 INIT,但在应用程序启动时出现异常- 告诉该表已经创建(org.h2.jdbc.JdbcSQLException: 表“USERS”已经存在;SQL 语句),我认为这是因为spring.datasource.initialize=true。所以......似乎 INITspring.datasource.initialize=true 不会一起工作。 @Maciej Kowalski application.conf 的正确设置是:spring.datasource.initialize=true spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password=最重要的是,不要忘记禁用 Hibernate 数据库初始化属性spring.jpa.hibernate.ddl-auto=none,因为默认值create-drop 将删除之前插入的表中的所有数据。你会有空桌子。 是的,那个 spring.jpa.hibernate.ddl-auto 可能已经妨碍了。很高兴它终于对你有用。 spring.jpa.hibernate.ddl-auto=none 导致我 h2 根本不创建任何表.... 感谢@tyomka。您设置 spring.jpa.hibernate.ddl-auto=none 的建议是使其正常工作的关键。它节省了我的时间。【参考方案2】:

当我在 application.properties 中添加以下行时,我解决了类似的问题:

spring.jpa.hibernate.ddl-auto=none
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.session.jdbc.initialize-schema=always
spring.sql.init.data-locations=classpath:schema.sql,classpath:data.sql

【讨论】:

以上是关于内存数据库H2中的Spring Boot在初始化时不会从文件中加载数据的主要内容,如果未能解决你的问题,请参考以下文章

内存数据库spring-boot中的h2

在 Spring Boot 应用程序上使用 Flyway 时如何在 H2 中加载初始数据?

Spring Boot 2.x 实践记:H2 Database

Spring Boot 2.x 实践记:H2 Database

Spring Boot 2.x 实践记:H2 Database

Spring Boot - 内存泄漏 - H2 数据库 - 不注销驱动程序