H2内存数据库.表未找到

Jor*_*orn 170 java database h2

我有一个带有URL的H2数据库"jdbc:h2:test".我使用创建一个表CREATE TABLE PERSON (ID INT PRIMARY KEY, FIRSTNAME VARCHAR(64), LASTNAME VARCHAR(64));.然后我使用这个(空)表选择所有内容SELECT * FROM PERSON.到现在为止还挺好.

但是,如果我将URL更改为"jdbc:h2:mem:test",唯一的区别是数据库现在只在内存中,这给了我一个org.h2.jdbc.JdbcSQLException: Table "PERSON" not found; SQL statement: SELECT * FROM PERSON [42102-154].我可能在这里遗漏了一些简单的东西,但任何帮助都会受到赞赏.

rei*_*901 304

hbm2ddl在创建表后关闭连接,所以h2丢弃它.

如果您的connection-url配置如下

jdbc:h2:mem:test
Run Code Online (Sandbox Code Playgroud)

在最后一次连接关闭时,数据库的内容将丢失.

如果你想保留你的内容,你必须像这样配置网址

jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
Run Code Online (Sandbox Code Playgroud)

如果这样做,只要vm存在,h2就会保留其内容.

  • 如果你在代码中使用小写来命名你的表,你应该知道H2大写一切默认使用DATABASE_TO_UPPER = false来避免它,例如jdbc:h2:mem:test; DB_CLOSE_DELAY = -1; DATABASE_TO_UPPER = false; (5认同)
  • 它必须是一个命名的内存数据库,即`jdbc:h2:mem :; DB_CLOSE_DELAY = -1`不起作用. (2认同)

Cri*_*bie 90

我知道这不是你的情况,但我遇到了同样的问题,因为H2正在创建具有大写名称的表,然后表现区分大小写,即使在所有脚本(包括创建脚本)中我使用小写.

通过添加;DATABASE_TO_UPPER=false到连接URL 解决.

  • 哇 - 我很高兴你分享了这个!从来没有想过这一点. (7认同)
  • 我怎样才能多次投票?非常感谢!这应该是第一个答案的一部分. (3认同)

Out*_*ONE 11

一个原因可能是jpa尝试在创建表结构之前插入数据,为了解决这个问题,在application.properties中插入这一行:

spring.jpa.defer-datasource-initialization=true
Run Code Online (Sandbox Code Playgroud)


Jos*_*ger 10

很难说.我创建了一个程序来测试这个:

package com.gigaspaces.compass;

import org.testng.annotations.Test;

import java.sql.*;

public class H2Test {
@Test
public void testDatabaseNoMem() throws SQLException {
    testDatabase("jdbc:h2:test");
}
@Test
public void testDatabaseMem() throws SQLException {
    testDatabase("jdbc:h2:mem:test");
}

private void testDatabase(String url) throws SQLException {
    Connection connection= DriverManager.getConnection(url);
    Statement s=connection.createStatement();
    try {
    s.execute("DROP TABLE PERSON");
    } catch(SQLException sqle) {
        System.out.println("Table not found, not dropping");
    }
    s.execute("CREATE TABLE PERSON (ID INT PRIMARY KEY, FIRSTNAME VARCHAR(64), LASTNAME VARCHAR(64))");
    PreparedStatement ps=connection.prepareStatement("select * from PERSON");
    ResultSet r=ps.executeQuery();
    if(r.next()) {
        System.out.println("data?");
    }
    r.close();
    ps.close();
    s.close();
    connection.close();
}
}
Run Code Online (Sandbox Code Playgroud)

测试完成,没有失败,也没有意外输出.您运行的是哪个版本的h2?


小智 9

For Spring Boot 2.4+ use spring.jpa.defer-datasource-initialization=true in application.properties

  • 点对点:)解决了我的问题。谢谢! (8认同)
  • 这确实是一个漂亮的解决方案。您能解释一下这个声明的作用吗? (7认同)

Dev*_*Dio 7

我试图添加

jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
Run Code Online (Sandbox Code Playgroud)

然而,这没有帮助。在H2 站点上,我发现了以下内容,在某些情况下确实可以提供帮助。

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

但是,我的问题是模式应该与默认模式不同。所以开始使用

JDBC URL: jdbc:h2:mem:test
Run Code Online (Sandbox Code Playgroud)

我不得不使用:

JDBC URL: jdbc:h2:mem:testdb
Run Code Online (Sandbox Code Playgroud)

然后桌子是可见的


nag*_*hun 7

打开 h2-console 时,JDBC URL 必须与属性中指定的匹配:

spring.datasource.driverClassName=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:testdb

spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true

spring.h2.console.enabled=true
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

这似乎很明显,但我花了几个小时弄清楚这一点..

  • 感谢您在接下来的几个小时内完成面试任务,并损失了几个宝贵的时间,直到我看到这条评论,这就是问题所在! (2认同)

Luk*_*ard 6

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • @Jorn:我可能不知道您要做什么,我是根据您提供的信息进行猜测的。提供展示您的问题的 SSCCE (http://sscce.org/) 可能更有帮助 - 在这方面我不会称您的问题为“完整”。我提供了上面的答案,因为 SO 上的人(主要是编程的新手)可能认为“内存中”数据库将数据存储在计算机内存中的某个地方,在那里它可以在程序调用之间幸存下来。你的问题不够完整,不足以让我相信你不是这些人中的一员。 (2认同)

小智 6

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

使用:

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

DatabaseMetaData metaData = connection.getMetaData();
...
metaData.getColumns(...);
Run Code Online (Sandbox Code Playgroud)

返回一个空的结果集。

但使用以下 URL 则可以正常工作:

String JDBC_URL = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false";
Run Code Online (Sandbox Code Playgroud)

需要指定:DATABASE_TO_UPPER=false

  • 这不会添加[this](/sf/answers/1254796791/)答案未涵盖的任何内容。[来自评论](https://stackoverflow.com/review/low-quality-posts/22862428)。 (2认同)

小智 5

通过创建一个新的 src/test/resources 文件夹 + 插入 application.properties 文件来解决,明确指定创建一个测试数据库:

spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=create
Run Code Online (Sandbox Code Playgroud)


Geo*_*eev 5

我遇到了同样的问题,并将 application-test.properties 中的配置更改为:

#Test Properties
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=create-drop
Run Code Online (Sandbox Code Playgroud)

还有我的依赖:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <version>1.4.198</version>
        <scope>test</scope>
    </dependency>
Run Code Online (Sandbox Code Playgroud)

以及测试类上使用的注释:

@RunWith(SpringRunner.class)
@DataJpaTest
@ActiveProfiles("test")
public class CommentServicesIntegrationTests {
...
}
Run Code Online (Sandbox Code Playgroud)