H2内存数据库。表未找到

时间:2011-04-23 10:51:30

标签: java database h2

我有一个带有网址"jdbc:h2:test"的H2数据库。我使用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]。我可能在这里遗漏了一些简单的东西,但任何帮助都会受到赞赏。

19 个答案:

答案 0 :(得分:283)

hbm2ddl在创建表后关闭连接,因此h2将其丢弃。

如果您的connection-url配置如下

jdbc:h2:mem:test

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

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

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

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

答案 1 :(得分:82)

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

通过将;DATABASE_TO_UPPER=false添加到连接网址来解决此问题。

答案 2 :(得分: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();
}
}

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

答案 3 :(得分: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();
    }
}

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

答案 4 :(得分:4)

我试图添加

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

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

  

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

然而,我的问题是只有架构应该与默认架构不同。因此无法使用

JDBC URL: jdbc:h2:mem:test

我不得不使用:

JDBC URL: jdbc:h2:mem:testdb

然后表格可见

答案 5 :(得分:1)

我正在尝试获取表元数据,但是出现以下错误:

使用:

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

答案 6 :(得分:1)

我在对Spring引导版本2.2.6的 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>

在application.yml中添加H2 DB配置-

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

答案 7 :(得分:1)

遇到了完全相同的问题,尝试了以上所有方法,但没有成功。 错误的相当有趣的原因是 JVM在创建数据库表之前启动太快(使用src.main.resources中的data.sql文件)。因此,在调用“ select * from person”之前,我放置了一个Thread.sleep(1000)计时器等待一秒钟。 现在可以正常工作。

application.properties:

spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

data.sql:

create table person
(
id integer not null,
name varchar(255) not null,
location varchar(255),
birth_date timestamp,
primary key(id)
);

insert into person values (
10001, 'Tofu', 'home', sysdate()
);

PersonJdbcDAO.java:

    public List<Person> findAllPersons(){
    return jdbcTemplate.query("select * from person", 
        new BeanPropertyRowMapper<Person>(Person.class));
}

主类:

Thread.sleep(1000);
logger.info("All users -> {}", dao.findAllPersons());

答案 8 :(得分:1)

我遇到了同样的问题,并将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

我的依赖项:

    <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>

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

@RunWith(SpringRunner.class)
@DataJpaTest
@ActiveProfiles("test")
public class CommentServicesIntegrationTests {
...
}

答案 9 :(得分:1)

我来到这个帖子是因为我有同样的错误。

在我的情况下,数据库演变没有被执行,所以表根本就没有。

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

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

  

播放使用多个演进脚本跟踪您的数据库演变。这些脚本使用普通的旧SQL编写,应位于应用程序的conf / evolutions / {database name}目录中。如果演进适用于您的默认数据库,则此路径为conf / evolutions / default。

我有一个名为 conf / evolutions.default 的文件夹,由eclipse创建。将文件夹结构更正为 conf / evolutions / default

后,问题就消失了

答案 10 :(得分:0)

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

spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=create

答案 11 :(得分:0)

打开h2-console时,JDBC URL必须与属性中指定的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

enter image description here

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

答案 12 :(得分:0)

<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>

答案 13 :(得分:0)

我已经尝试了上述解决方案,但就控制台的建议而言,在我的情况下添加了属性 DB_CLOSE_ON_EXIT = FALSE ,它解决了该问题。

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

答案 14 :(得分:0)

我尝试添加;DATABASE_TO_UPPER=false参数,该参数确实可以完成一次测试,但是对我来说,诀窍是;CASE_INSENSITIVE_IDENTIFIERS=TRUE

我当时有:jdbc:h2:mem:testdb;CASE_INSENSITIVE_IDENTIFIERS=TRUE

此外,对我来说,问题是当我升级到Spring Boot 2.4.1时。

答案 15 :(得分:0)

在我的情况下,jpa 测试期间发生了缺失表错误,表是由 schem.sql 文件创建的,在测试 @org.springframework.transaction.annotation.Transactional 后问题得到解决

答案 16 :(得分:0)

适用于 Spring Boot 2.4+ 采用 spring.jpa.defer-datasource-initialization=true 在 application.properties 中

答案 17 :(得分:0)

我参加聚会可能有点晚了,但我遇到了完全相同的错误,我尝试了这里和其他网站上提到的几乎所有解决方案,例如 DATABASE_TO_UPPER=false;DB_CLOSE_DELAY=-1; DB_CLOSE_ON_EXIT=假;忽略情况=真

但对我来说没有任何效果。 对我有用的是将 data.sql 重命名为 import.sql

我在这里找到的 - https://stackoverflow.com/a/53179547/8219358

对于 Spring Boot 2.4+,在 application.properties 中使用 spring.jpa.defer-datasource-initialization=true(此处提到 - https://stackoverflow.com/a/68086707/8219358

我意识到其他解决方案更合乎逻辑,但没有一个对我有用,而这确实有效。

答案 18 :(得分:-2)

Time.sleep(1000);

这对我有用。只是尝试一下,如果您的PC速度很慢,则可以增加线程的持续时间,以使DB正常工作,并且JVM可以获取我们的表。