我有一个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]。我可能错过了一些简单的东西,但任何帮助将不胜感激。


当前回答

我试图获取表元数据,但有以下错误:

使用:

String JDBC_URL = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1";

DatabaseMetaData metaData = connection.getMetaData();
...
metaData.getColumns(...);

返回一个空的ResultSet。

但是使用下面的URL可以正常工作:

String JDBC_URL = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false";

需要指定:DATABASE_TO_UPPER=false

其他回答

<bean id="benchmarkDataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="org.h2.Driver" />
    <property name="url" value="jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1" />
    <property name="username" value="sa" />
    <property name="password" value="" />
</bean>

我已经尝试了上面的解决方案,但在我的情况下,在控制台中添加属性DB_CLOSE_ON_EXIT=FALSE,它修复了这个问题。

 spring.datasource.url=jdbc:h2:mem:testdb;DATABASE_TO_UPPER=false;DB_CLOSE_ON_EXIT=FALSE

我尝试添加;DATABASE_TO_UPPER=false参数,它在单个测试中确实起作用,但对我来说起作用的是;CASE_INSENSITIVE_IDENTIFIERS=TRUE。

最后,我得到:jdbc:h2:mem:testdb;CASE_INSENSITIVE_IDENTIFIERS=TRUE

此外,当我升级到Spring Boot 2.4.1时,我遇到了这个问题。

也有类似的问题 解决方案是向application.properties添加以下内容

spring.jpa.defer-datasource-initialization=true

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类查找。