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]()
Что кажется очевидным, но я потратил часы, чтобы понять это..