H2 в памяти. Таблица не найдена

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

Ответ 1

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

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

jdbc:h2:mem:test

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

Если вы хотите сохранить свой контент, вам нужно настроить URL-адрес, подобный этому

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

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

Ответ 2

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

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

Ответ 3

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

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

Ответ 4

В базе данных 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.

Ответ 5

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

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

Затем были видны таблицы

Ответ 6

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

С помощью:

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

Ответ 7

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

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

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

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

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

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

Ответ 8

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

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

Ответ 10

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

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

Ответ 11

При открытии h2-консоли URL JDBC должен совпадать с тем, который указан в свойствах:

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

Что кажется очевидным, но я потратил часы, чтобы понять это..