我有一个H2数据库的URL“jdbc: H2:test”。我使用create table PERSON (ID INT主键,名字VARCHAR(64),姓VARCHAR(64));;然后使用select * from PERSON从这个(空)表中选择所有内容。到目前为止,一切顺利。

然而,如果我将URL更改为“jdbc:h2:mem:test”,唯一的区别是数据库现在只在内存中,这给了我一个org.h2.jdbc。JdbcSQLException:表“PERSON”未找到;SQL语句:SELECT * FROM PERSON[42102-154]。我可能错过了一些简单的东西,但任何帮助将不胜感激。


当前回答

H2内存数据库将数据存储在JVM内部的内存中。当JVM退出时,这些数据就丢失了。

我怀疑您正在做的事情与下面的两个Java类类似。其中一个类创建了一个表,而另一个类尝试插入表:

import java.sql.*;

public class CreateTable {
    public static void main(String[] args) throws Exception {
        DriverManager.registerDriver(new org.h2.Driver());
        Connection c = DriverManager.getConnection("jdbc:h2:mem:test");
        PreparedStatement stmt = c.prepareStatement("CREATE TABLE PERSON (ID INT PRIMARY KEY, FIRSTNAME VARCHAR(64), LASTNAME VARCHAR(64))");
        stmt.execute();
        stmt.close();
        c.close();
    }
}

and

import java.sql.*;

public class InsertIntoTable {
    public static void main(String[] args) throws Exception {
        DriverManager.registerDriver(new org.h2.Driver());
        Connection c = DriverManager.getConnection("jdbc:h2:mem:test");
        PreparedStatement stmt = c.prepareStatement("INSERT INTO PERSON (ID, FIRSTNAME, LASTNAME) VALUES (1, 'John', 'Doe')");
        stmt.execute();
        stmt.close();
        c.close();
    }
}

当我一个接一个地运行这些类时,我得到了以下输出:

C:\Users\Luke\stuff>java CreateTable

C:\Users\Luke\stuff>java InsertIntoTable
Exception in thread "main" org.h2.jdbc.JdbcSQLException: Table "PERSON" not found; SQL statement:
INSERT INTO PERSON (ID, FIRSTNAME, LASTNAME) VALUES (1, 'John', 'Doe') [42102-154]
        at org.h2.message.DbException.getJdbcSQLException(DbException.java:327)
        at org.h2.message.DbException.get(DbException.java:167)
        at org.h2.message.DbException.get(DbException.java:144)
        ...

一旦第一个java进程退出,由CreateTable创建的表就不再存在。因此,当InsertIntoTable类出现时,没有供它插入的表。

当我将连接字符串更改为jdbc:h2:test时,我发现没有这样的错误。我还发现出现了一个文件test.h2.db。这是H2放置表的位置,因为它存储在磁盘上,所以表仍然在那里,供InsertIntoTable类查找。

其他回答

我已经试着补充了

jdbc:h2:mem:test;DB_CLOSE_DELAY=-1

然而,这并没有帮助。在H2网站上,我发现以下,这确实可以在某些情况下有所帮助。

默认情况下,关闭到数据库的最后一个连接将关闭数据库。对于内存中的数据库,这意味着内容丢失。要保持数据库打开,在数据库URL中添加;DB_CLOSE_DELAY=-1。要在虚拟机处于活动状态时保持内存中数据库的内容,请使用jdbc:h2:mem:test;DB_CLOSE_DELAY=-1。

然而,我的问题是模式应该与默认模式不同。所以不用

JDBC URL: jdbc:h2:mem:test

我不得不使用:

JDBC URL: jdbc:h2:mem:testdb

然后桌子就可见了

我来这个职位是因为我也犯了同样的错误。

在我的例子中,数据库演化没有被执行,所以表根本就不存在。

我的问题是进化脚本的文件夹结构是错误的。

来自:https://www.playframework.com/documentation/2.0/Evolutions

Play使用多个演进脚本跟踪数据库演进。这些脚本是用普通的SQL编写的,应该位于应用程序的conf/evolution /{数据库名}目录中。如果演进应用于默认数据库,则该路径为conf/evolutions/default。

我在eclipse中创建了一个名为conf/evolution .default的文件夹。在我将文件夹结构修正为conf/evolution /default后,这个问题消失了

在我的情况下,缺少表错误发生在jpa测试期间,表是由方案创建的。SQL文件,问题在放置@org.springframework.transaction.annotation后被修复。测试中的事务性

Spring Boot 2.4+ 使用 spring.jpa.defer-datasource-initialization = true 在application.properties

在添加Spring Data JPA依赖项后,我发现它可以正常工作

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>

在应用程序中添加H2 DB配置。yml:

spring:
  datasource:
    driverClassName: org.h2.Driver
    initialization-mode: always
    username: sa
    password: ''
    url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
  h2:
    console:
      enabled: true
      path: /h2
  jpa:
    database-platform: org.hibernate.dialect.H2Dialect
    hibernate:
      ddl-auto: none