H2 인 메모리 데이터베이스. 테이블을 찾을 수 없습니다


183

URL이있는 H2 데이터베이스가 "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]. 아마도 여기에 간단한 것이 빠져 있지만 도움이 될 것입니다.


2
인 메모리 모드로 전환 한 후 테이블을 Person다시 만들어야 합니다. H2는 이전에 디스크에서 만든 데이터베이스에 대해 아무것도 모릅니다.
Benjamin Muschko

나머지 프로그램은 변경되지 않았습니다. 테이블을 다시 만들었습니다.
Jorn

답변:


331

DB_CLOSE_DELAY=-1

hbm2ddl은 테이블을 생성 한 후 연결을 닫으므로 h2는 삭제합니다.

연결 URL을 다음과 같이 구성한 경우

jdbc:h2:mem:test

마지막 연결이 닫히는 순간 데이터베이스의 내용이 손실됩니다.

콘텐츠를 유지하려면 다음과 같이 URL을 구성해야합니다

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

그렇게하면 h2vm 이 유지되는 동안 내용을 유지합니다 .

콜론 ( ;)이 아니라 세미콜론 ( )을 확인 하십시오 :.

참고 항목 인 - 메모리 데이터베이스 의 섹션 기능 페이지를. 인용 :

기본적으로 데이터베이스에 대한 마지막 연결을 닫으면 데이터베이스가 닫힙니다. 인 메모리 데이터베이스의 경우 이는 내용이 손실되었음을 의미합니다. 데이터베이스를 열어 두려면 ;DB_CLOSE_DELAY=-1데이터베이스 URL에 추가하십시오 . 가상 머신이 활성 상태 인 한 인 메모리 데이터베이스의 컨텐츠를 유지하려면을 사용하십시오 jdbc:h2:mem:test;DB_CLOSE_DELAY=-1.


그동안 문제를 직접 발견했지만 완전히 맞습니다. 감사!
Jorn

3
그리고 이름이 지정된 인 메모리 데이터베이스 여야합니다 jdbc:h2:mem:;DB_CLOSE_DELAY=-1. 즉, 작동하지 않습니다.
피터 베커

메모리 대신 파일에 데이터를 어떻게 저장할 수 있습니까?
Suleman khan

9
코드에서 테이블 이름을 지정하기 위해 소문자를 사용하는 경우 H2는 기본적으로 DATABASE_TO_UPPER = false를 사용하여 피해야합니다. 예 : jdbc : h2 : mem : test; DB_CLOSE_DELAY = -1; DATABASE_TO_UPPER = false;
Oleksandr Petrenko

@OleksandrPetrenko-그 후행 ';' 문제를 일으키는 것 같습니다. 나는 당신이 그것을 배제해야한다고 생각합니다.
Volksman

103

나는 이것이 당신의 경우가 아니라는 것을 알고 있지만 H2는 대문자로 이름을 가진 테이블을 만든 다음 모든 스크립트 (작성 스크립트 포함)에서 소문자를 사용하더라도 대소 문자를 구분하므로 동일한 문제가 발생했습니다.

;DATABASE_TO_UPPER=false연결 URL 에 추가 하여 해결했습니다 .


7
와우-이 글을 공유하게되어 매우 기쁩니다! 결코 그런 생각을하지 않았을 것입니다.
ms-tg 2013

1
묻는 질문에 대한 해결책이 아니라 같은 질문으로 검색 할 때 발생했던 문제에 대한 해결책입니다!
Yaytay

DATABASE_TO_UPPER=false스크립트를 init 스크립트에서 SQL 문으로 설정할 수 있습니까? (와 같은 문장과 유사합니다 SET MODE PostgreSQL;) 그렇다면 정확한 구문은 무엇입니까?
Jonik

3
어떻게 여러 번 공표 할 수 있습니까? 고마워요! 이것은 첫 번째 답변의 일부 여야합니다.
Ribesg

11

말하기 어렵다. 이것을 테스트하는 프로그램을 만들었습니다.

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 버전은 제가 오늘 사이트를 떠난 버전입니다. 1.3.154
Jorn

1
문제를 발견 한 것 같습니다. 연결을 닫으면 테이블이 생성 된 다음 새 연결을 열면 db가 사라집니다. 이전 연결을 닫기 전에 새 연결을 열면 데이터가 유지됩니다. 파일을 사용할 때 데이터는 (분명히) 항상 남아 있습니다.
Jorn

7

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
스레드 "main"의 예외 org.h2.jdbc.JdbcSQLException : "PERSON"테이블을 찾을 수 없습니다. SQL 문 :
사람 (ID, 성, 이름)에 삽입 (1, 'John', 'Doe') [42102-154]
        org.h2.message.DbException.getJdbcSQLException (DbException.java:327)에서
        org.h2.message.DbException.get (DbException.java:167)에서
        org.h2.message.DbException.get (DbException.java:144)에서
        ...

첫 번째 java프로세스가 종료 되 자마자 생성 한 테이블이 CreateTable더 이상 존재하지 않습니다. 따라서 InsertIntoTable 클래스가 나오면 삽입 할 테이블이 없습니다.

연결 문자열을로 변경하면 jdbc:h2:test이러한 오류가 없음을 발견했습니다. 나는 또한 파일 test.h2.db이 나타났음을 발견했다 . 이것은 H2가 테이블을 넣은 위치였으며 디스크에 저장되었으므로 InsertIntoTable 클래스를 찾을 수있는 테이블이 여전히있었습니다.


1
제발 참고 것을 registerDriver()호출은 불필요 : 첫째 : 간단한의 Class.forName을 ()는 대부분의 JDBC 드라이버를 동일하지 자바 6가 핀클 위해 (더 중요한)가 완전히 불필요되는에 자동 검출 (호환) JDBC 드라이버 클래스 패스.
Joachim Sauer

인 메모리 db는 메모리를 소유 한 프로그램이 실행되는 동안에 만 존재합니까? 와우, 나는 몰랐다> _ <그러나 실제로, 나는 내가 무엇을하려고하는지 알고있다. 당신의 대답을 읽고, 나는 당신이 확실하지 않습니다.
Jorn

2
@ 조 : 나는 당신이 무엇을하려고하는지 모를 수도 있습니다, 나는 당신이 제공 한 정보를 기반으로 추측하고 있습니다. 문제를 보여주는 SSCCE ( sscce.org ) 를 제공하는 것이 도움이 될 수 있습니다 . 그런 점에서 귀하의 질문을 '완전한'것으로 부르지 않겠습니다. '메모리 내'데이터베이스가 프로그램 호출 사이에서 살아남을 수있는 곳의 컴퓨터 메모리에 데이터를 저장한다고 생각할 수있는 SO (주로 프로그래밍 초보자)에 사람들이 있기 때문에 위의 대답을 제공했습니다. 귀하의 질문은 귀하가이 사람들 중 하나가 아니라는 것을 확신시키기에 충분하지 않았습니다.
Luke Woodward

5

나는 추가하려고했습니다

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

그러나 그것은 도움이되지 못했습니다. 온 H2 사이트 , 난 정말 어떤 경우에 도움이 될 다음을 발견했다.

기본적으로 데이터베이스에 대한 마지막 연결을 닫으면 데이터베이스가 닫힙니다. 인 메모리 데이터베이스의 경우 이는 내용이 손실되었음을 의미합니다. 데이터베이스를 열어 두려면; DB_CLOSE_DELAY = -1을 데이터베이스 URL에 추가하십시오. 가상 머신이 활성 상태 인 한 인 메모리 데이터베이스의 컨텐츠를 유지하려면 jdbc : h2 : mem : test; DB_CLOSE_DELAY = -1을 사용하십시오.

그러나 내 문제는 스키마 만 기본 스키마와 달라야한다는 것입니다. 그래서 사용의 insted

JDBC URL: jdbc:h2:mem:test

나는 사용해야했다 :

JDBC URL: jdbc:h2:mem:testdb

그런 다음 테이블이 보입니다.


감사합니다. "testdb"는 저에게도 수정되었습니다 ( "DB_CLOSE_DELAY = -1"에 추가)!
boly38

4

나는 같은 문제가 있었고 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 {
...
}

3

테이블 메타 데이터를 가져 오려고했지만 다음 오류가 발생했습니다.

사용 :

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 를 지정해야했습니다.


이 적용되지 아무것도 추가하지 않습니다 대답을. 검토에서 .
Wai Ha Lee

3

h2- 콘솔을 열 때 JDBC 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

여기에 이미지 설명을 입력하십시오

분명해 보이지만 이것을 알아내는 데 몇 시간이 걸렸습니다 ..


2

새로운 src / test / resources 폴더 + insert application.properties 파일을 작성하여 명시 적으로 테스트 dbase를 작성하도록 지정하여 해결했습니다.

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

1

나는 같은 오류가 있었기 때문에이 게시물에 왔습니다.

필자의 경우 데이터베이스 진화가 실행되지 않았으므로 테이블이 전혀 없었습니다.

내 문제는 진화 스크립트의 폴더 구조가 잘못되었다는 것입니다.

에서 : https://www.playframework.com/documentation/2.0/Evolutions

Play는 여러 가지 진화 스크립트를 사용하여 데이터베이스 진화를 추적합니다. 이 스크립트는 일반 SQL로 작성되었으며 응용 프로그램의 conf / evolutions / {database name} 디렉토리에 있어야합니다. 진화가 기본 데이터베이스에 적용되는 경우이 경로는 conf / evolutions / default입니다.

나는 이클립스가 만든 conf / evolutions.default 라는 폴더를 가지고 있었다 . 폴더 구조를 conf / evolutions / default 로 수정 한 후 문제가 사라졌습니다.


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

0

똑같은 문제가 있었지만 위의 모든 것을 시도했지만 성공하지 못했습니다. 다소 재미있는 오류의 원인은 DB 테이블이 생성되기 전에 (src.main.resources의 data.sql 파일 사용) JVM이 너무 빨리 시작했기 때문 입니다. 그래서 "select * from person"을 호출하기 전에 Thread.sleep (1000) 타이머를 1 초 정도 기다렸습니다. 이제 완벽하게 작동합니다.

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

0

Spring 부트 버전 2.2.6에서 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>

application.yml에 H2 DB 구성 추가-

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

0

이 구성을 추가하여 솔루션을 찾았습니다.

spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

전체 구성 (단순한 spring.datasource.url 사용) :

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=sa
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=create-drop

내가 함께 일하고 있어요 H2 버전 1.4.200봄 부팅 2.2.6.RELEASE


-2

수면 (1000);

이것은 나를 위해 일한 것입니다. 시도해보기 위해 PC가 느리면 스레드의 지속 시간을 늘려 DB가 제대로 작동하고 JVM이 테이블을 가져올 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.