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


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

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 ?


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


DB_CLOSE_DELAY = 1

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

如果您像这样配置了connection-url

jdbc:h2:mem:test

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

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

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

如果这样做,h2将保留它的内容,只要vm存在。

注意分号(;)而不是冒号(:)。

请参阅功能页面的内存数据库部分。引用:

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


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

通过向连接URL添加;DATABASE_TO_UPPER=false来解决。


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

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

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

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

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

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


我已经试着补充了

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

然后桌子就可见了


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

通过创建一个新的src/test/resources文件夹+插入应用程序来解决。属性文件,显式指定创建test dbase:

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

我也遇到了同样的问题,并在应用程序测试中更改了配置。属性:

#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 {
...
}

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

使用:

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


当打开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

这似乎是显而易见的,但我花了几个小时来解决这个问题。


同样的问题,尝试了以上所有方法,但都没有成功。 导致这个错误的一个相当有趣的原因是,在创建DB表之前,JVM启动得太快了(使用data。src.main.resources中的SQL文件)。所以我设置了一个Thread.sleep(1000)定时器,在调用“select * from person”之前等待一秒钟。 现在工作完美无缺。

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());

在添加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

我已经尝试了上面的解决方案,但在我的情况下,在控制台中添加属性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时,我遇到了这个问题。


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


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


我可能有点晚了,但我遇到了完全相同的错误,我尝试了这里提到的每个解决方案和其他网站,如DATABASE_TO_UPPER=false;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT = FALSE;IGNORECASE = TRUE

但对我来说什么都不管用。 对我有用的是重命名数据。导入。SQL

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

Or

对于Spring Boot 2.4+,在应用程序中使用Spring .jpa.defer-datasource-initialization=true。属性(此处提到- https://stackoverflow.com/a/68086707/8219358)

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


在我的例子中,我为表H2 Database中的列名使用了特殊的关键字。如果您正在使用不同的数据库,则避免在不同的数据库中使用这些特殊的关键字。Spring和Hibernate不够聪明,不能准确地告诉您哪些列名是禁止的,或者在表创建过程中哪里出现了错误。 关键词如;

描述,间隔,度量

为了解决我遇到的问题,我将这些字段重命名为:

Descr, time_interval, time_metric

http://www.h2database.com/html/advanced.html


   Use the same in applications.properties file
   
   spring.jpa.show-sql=true
   spring.datasource.url=jdbc:h2:mem:testdb;DATABASE_TO_UPPER=false
   DB_CLOSE_ON_EXIT=FALSE
   spring.data.jpa.repositories.bootstrap-mode=default
   spring.h2.console.enabled=true spring.jpa.generate-ddl=true
   spring.jpa.hibernate.ddl-auto=create
   spring.datasource.driverClassName=org.h2.Driver
   spring.jpa.defer-datasource-initialization=true

一个原因可能是jpa试图在创建表结构之前插入数据,为了解决这个问题,在应用程序中插入这一行。属性:

spring.jpa.defer-datasource-initialization=true

如果在生成表时出现错误,也会发生此问题。

如果实体使用了H2不支持的任何特性(例如,指定了一个非标准的columnDefinition),模式生成将失败,测试将在不生成数据库的情况下继续进行。

在这种情况下,在日志的某个地方你会发现:

WARN ExceptionHandlerLoggedImpl: GenerationTarget encountered exception accepting command :
 Error executing DDL "create table ..." via JDBC Statement

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

spring.jpa.defer-datasource-initialization=true


Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "user" not found; SQL statement:

在我的情况下,我的表名是用户,但从H2 2.1.212用户是保留的,所以不能使表

@Table(name="users"

datasource:
  url: jdbc:h2:mem:testdb;DATABASE_TO_UPPER=false;DB_CLOSE_DELAY=-1;

现在起作用了