即使我使用 DB_CLOSE_DELAY=-1 报告 H2 内存数据库也找不到表

Posted

技术标签:

【中文标题】即使我使用 DB_CLOSE_DELAY=-1 报告 H2 内存数据库也找不到表【英文标题】:H2 in-memory database even if I use DB_CLOSE_DELAY=-1 reports Table not found 【发布时间】:2021-04-23 08:18:34 【问题描述】:

我正在使用 h2 数据库作为 maven 项目的依赖项:

 <dependency>
         <groupId>com.h2database</groupId>
         <artifactId>h2</artifactId>
         <version>1.4.200</version>
 </dependency>

要使用in-memory mode我已经配置了application.properties文件:

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

如提到的here 和here,因为对于变体:jdbc:h2:mem:test

数据库的内容在最后一次连接的那一刻丢失 已关闭。

同时,我使用 Intelij Idea 配置了数据源

下一步,我已经使用带有 h2-dialect 的脚本成功填充了数据:

CREATE TABLE users
(
    id    int NOT NULL GENERATED BY DEFAULT AS IDENTITY,
    login varchar(10),
    PRIMARY KEY (id),
    UNIQUE (login)
);
CREATE TABLE teams
(
    id   int NOT NULL GENERATED BY DEFAULT AS IDENTITY,
    name varchar(10),
    PRIMARY KEY (id)
);
CREATE TABLE users_teams
(
    user_id int,
    team_id int,
    FOREIGN KEY (user_id)
        REFERENCES users (id) ON DELETE CASCADE,
    FOREIGN KEY (team_id)
        REFERENCES teams (id) ON DELETE CASCADE,
    UNIQUE (
            user_id,
            team_id
        )
);

填充后连接没有关闭,但是如果我在连接过程中运行程序,我仍然会收到错误:

jan 19, 2021 3:50:01 AM com.epam.rd.java.basic.practice8.db.DBManager insertUser
Table "USERS" not found; SQL statement:
INSERT INTO users (login) VALUES ('petrov'); [42102-200]
jan 19, 2021 3:50:01 AM com.epam.rd.java.basic.practice8.db.DBManager insertUser
Table "USERS" not found; SQL statement:
INSERT INTO users (login) VALUES ('obama'); [42102-200]
jan 19, 2021 3:50:01 AM com.epam.rd.java.basic.practice8.db.DBManager findAllUsers
Table "USERS" not found; SQL statement:
SELECT * FROM users; [42102-200]
jan 19, 2021 3:50:01 AM com.epam.rd.java.basic.practice8.db.DBManager insertTeam
Table "TEAMS" not found; SQL statement:
INSERT INTO teams (name) VALUES ('teamB'); [42102-200]
jan 19, 2021 3:50:01 AM com.epam.rd.java.basic.practice8.db.DBManager insertTeam
Table "TEAMS" not found; SQL statement:
INSERT INTO teams (name) VALUES ('teamC'); [42102-200]
jan 19, 2021 3:50:01 AM com.epam.rd.java.basic.practice8.db.DBManager findAllTeams
Table "TEAMS" not found; SQL statement:
SELECT * FROM teams; [42102-200]
jan 19, 2021 3:50:01 AM com.epam.rd.java.basic.practice8.db.DBManager getUser
Table "USERS" not found; SQL statement:
SELECT * FROM users WHERE users.login='petrov'; [42102-200]
jan 19, 2021 3:50:01 AM com.epam.rd.java.basic.practice8.db.DBManager getUser
Table "USERS" not found; SQL statement:
SELECT * FROM users WHERE users.login='ivanov'; [42102-200]
jan 19, 2021 3:50:01 AM com.epam.rd.java.basic.practice8.db.DBManager getUser
Table "USERS" not found; SQL statement:
SELECT * FROM users WHERE users.login='obama'; [42102-200]
jan 19, 2021 3:50:01 AM com.epam.rd.java.basic.practice8.db.DBManager returnTeam
Table "TEAMS" not found; SQL statement:
SELECT * FROM teams WHERE teams.name='teamA'; [42102-200]
jan 19, 2021 3:50:01 AM com.epam.rd.java.basic.practice8.db.DBManager returnTeam
Table "TEAMS" not found; SQL statement:
SELECT * FROM teams WHERE teams.name='teamB'; [42102-200]
jan 19, 2021 3:50:01 AM com.epam.rd.java.basic.practice8.db.DBManager returnTeam
Table "TEAMS" not found; SQL statement:
SELECT * FROM teams WHERE teams.name='teamC'; [42102-200]
jan 19, 2021 3:50:01 AM com.epam.rd.java.basic.practice8.db.DBManager findAllUsers
Table "USERS" not found; SQL statement:
SELECT * FROM users; [42102-200]
Exception in thread "main" java.lang.NullPointerException
===========================
===========================
===========================
    at com.epam.rd.java.basic.practice8.Demo.main(Demo.java:382)

我也试过用:

jdbc:h2:mem:test;IFEXISTS=FALSE

如here 所述,但在连接过程中出现同样的问题。

演示类的逻辑如下:

public class Demo 

    private static <T> void printList(List<T> list) 
        for (T element : list) 
            System.out.println(element);
        
    

    public static void main(String[] args) 

        DBManager dbManager = DBManager.getInstance();

        dbManager.insertUser(User.createUser("petrov"));
        dbManager.insertUser(User.createUser("obama"));

        printList(dbManager.findAllUsers());

        System.out.println("===========================");

        dbManager.insertTeam(Team.createTeam("teamB"));
        dbManager.insertTeam(Team.createTeam("teamC"));

        printList(dbManager.findAllTeams());

        System.out.println("===========================");

        User userPetrov = dbManager.getUser("petrov");
        User userIvanov = dbManager.getUser("ivanov");
        User userObama = dbManager.getUser("obama");

        Team teamA = dbManager.getTeam("teamA");
        Team teamB = dbManager.getTeam("teamB");
        Team teamC = dbManager.getTeam("teamC");

        dbManager.setTeamsForUser(userIvanov, teamA);
        dbManager.setTeamsForUser(userPetrov, teamA, teamB);
        dbManager.setTeamsForUser(userObama, teamA, teamB, teamC);

        for (User user : dbManager.findAllUsers()) 
            printList(dbManager.getUserTeams(user));
            System.out.println("~~~~~");
        

        System.out.println("===========================");

        dbManager.deleteTeam(teamA);

        teamC.setName("teamX");
        dbManager.updateTeam(teamC);

        printList(dbManager.findAllTeams());
    

谁能解释一下,为什么会出现这个错误:

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

【问题讨论】:

【参考方案1】:

您从 IntelliJ 启动的 H2 的嵌入式内存实例在不同的进程中运行,并且与您的应用程序的嵌入式 H2 实例无关。您正在处理两个独立的数据库,您的应用程序看不到您使用 IntelliJ 创建的表。

如果您需要使用嵌入式内存数据库,那么您还需要从应用程序本身创建数据库架构。例如,通过executing a SQL script on connection 或使用架构演化工具,如Flyway 或Liquibase。 Spring Boot 等框架也可以配置为执行Database Initialisation

如果您确实需要多个进程来访问同一个数据库实例,那么您需要在 Server Mode 中运行 H2(如果您从应用程序以编程方式启动服务器,它适用于内存数据库)或 @987654326 @(不适用于内存数据库)。

【讨论】:

以上是关于即使我使用 DB_CLOSE_DELAY=-1 报告 H2 内存数据库也找不到表的主要内容,如果未能解决你的问题,请参考以下文章

java.lang.reflect.InvocationTargetException错误,改不好……之前可以的,即使恢复原样了,还是报错。

Xampp Apache 无法访问端口 80,即使它没有被使用

Python中在进行赋值运算时即使两侧操作数的类型不同也不会报错?

H2 数据库中的错误,同时运行多个测试

.net StreamReader .Readline报内存溢出OutOfMemory,求助!!

选择表单更改,弹出警报然后发送表单