База данных H2 в памяти. Таблица не найдена - PullRequest
163 голосов
/ 23 апреля 2011

У меня есть база данных H2 с URL "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]. Я, наверное, упускаю что-то простое здесь, но любая помощь будет признательна.

Ответы [ 10 ]

289 голосов
/ 09 мая 2011

hbm2ddl закрывает соединение после создания таблицы, поэтому h2 удаляет его.

Если ваш URL-адрес соединения настроен так:

jdbc:h2:mem:test

содержимое базы данных теряется прив момент закрытия последнего соединения.

Если вы хотите сохранить свой контент, вам нужно настроить URL следующим образом:

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

Если это так, h2 будетсохраняйте его содержимое до тех пор, пока живет vm .

86 голосов
/ 29 июля 2013

Я знаю, что это был не ваш случай, но у меня была та же проблема, потому что H2 создавал таблицы с именами UPPERCASE, тогда они вели себя с учетом регистра, хотя во всех сценариях (в том числе в сценариях создания) я использовал строчные буквы.

Решается добавлением ;DATABASE_TO_UPPER=false к URL-адресу соединения.

10 голосов
/ 23 апреля 2011

Трудно сказать.Я создал программу для проверки этого:

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 вы используете?

6 голосов
/ 23 апреля 2011

База данных 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 голосов
/ 25 декабря 2016

Я пытался добавить

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

Однако это не помогло. На сайте H2 я обнаружил следующее, что в некоторых случаях могло бы помочь.

По умолчанию закрытие последнего соединения с базой данных закрывает базу данных. Для базы данных в памяти это означает, что содержимое потеряно. Чтобы оставить базу данных открытой, добавьте; 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

Тогда таблицы были видны

1 голос
/ 26 апреля 2019

Я пытался получить метаданные таблицы, но имел следующую ошибку:

Использование:

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

1 голос
/ 04 апреля 2019

У меня была такая же проблема, и я изменил свою конфигурацию в 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 {
...
}
1 голос
/ 24 декабря 2014

Я пришел к этому сообщению, потому что у меня была та же ошибка.

В моем случае эволюция базы данных не была выполнена, поэтому таблицы там вообще не было.

Мойпроблема заключалась в том, что структура папок для сценариев эволюции была неправильной.

from: https://www.playframework.com/documentation/2.0/Evolutions

Воспроизведение отслеживает эволюцию вашей базы данных с использованием сценария нескольких эволюций.Эти сценарии написаны на простом старом SQL и должны находиться в каталоге conf / evolutions / {database name} вашего приложения.Если эволюции применяются к вашей базе данных по умолчанию, этот путь будет conf / evolutions / default.

У меня была папка с именем conf / evolutions.default , созданная eclipse.Проблема исчезла после того, как я исправил структуру папок в conf / evolutions / default

0 голосов
/ 03 января 2019

Решено путем создания новой папки src / test / resources + вставки файла application.properties с явным указанием создания тестовой базы данных:

spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=create
0 голосов
/ 31 декабря 2016
<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>
...