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は、以前にディスク上に作成したデータベースについて何も知りません。
ベンジャミンムシュコ

プログラムの残りの部分は変更されていません。テーブルを再度作成しました。
ジョーン

回答:


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


私はその間に自分自身で問題を見つけましたが、そうです、これは完全に正しいです。ありがとう!
ジョーン

3
そして、それは名前付きのインメモリデータベースでなければなりjdbc:h2:mem:;DB_CLOSE_DELAY=-1ません、すなわち動作しません。
Peter Becker 14

メモリではなくファイルにデータを保存するにはどうすればよいですか?
スレマンカーン2016年

9
コードでテーブルの名前に小文字を使用する場合、H2はすべてデフォルトでDATABASE_TO_UPPER = falseを使用してそれを回避することを知っておく必要があります。
Oleksandr Petrenko 2017年

@OleksandrPetrenko-末尾の「;」問題を引き起こすようです。あなたはそれを省く必要があると思います。
Volksman、

104

私はこれがあなたのケースではないことを知っていますが、すべてのスクリプト(作成スクリプトを含む)で小文字を使用していても、H2が大文字の名前でテーブルを作成し、大文字と小文字を区別するため、同じ問題がありました。

;DATABASE_TO_UPPER=false接続URLに追加することで解決します。


7
うわー-これを共有してくれてとても嬉しいです!そんなことは考えられなかったでしょう。
ms-tg 2013年

1
尋ねられた質問の解決策ではなく、同じ質問で検索するときに私が抱えていた問題の解決策!
Yaytay、2015年

これをDATABASE_TO_UPPER=falseinitスクリプトのSQLステートメントとして設定することは可能ですか?(のようなステートメントと同様にSET MODE PostgreSQL;)その場合、正確な構文は何ですか?
Jonik 2015年

3
これを複数回賛成するにはどうすればよいですか?どうもありがとう!これは最初の答えの一部になるはずです。
Ribesg 2017

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
私は問題を見つけたと思います。テーブルの作成に使用した接続を閉じてから、新しい接続を開くと、データベースが消えてしまいます。以前の接続を閉じる前に新しい接続を開くと、データが残ります。ファイルを使用すると、データは(明らかに)常に残ります。
2009

7

H2インメモリデータベースは、JVM内のメモリにデータを格納します。JVMが終了すると、このデータは失われます。

あなたがやっていることは、以下の2つのJavaクラスに似ていると思います。これらのクラスの1つはテーブルを作成し、もう1つはそのテーブルへの挿入を試みます。

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ステートメント:
INSERT INTO PERSON(ID、FIRSTNAME、LASTNAME)VALUES(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()呼び出しは不要であることに注意してください。最初に、ほとんどのJDBCドライバーに対して単純なClass.forName()が同じことを行い、(さらに重要なこと)Java 6が完全に不要で、(互換性のある)JDBCドライバーを自動検出します。クラスパス。
Joachim Sauer

メモリ内DBは、メモリを所有するプログラムが実行されている間だけ存在しますか?うわー、私は何も知りませんでした> _ <しかし、実際、私が何をしようとしているのかはわかっています。あなたの答えを読んで、あなたがそうするかはわかりません。
ジョーン

2
@ジョン:あなたが何をしようとしているのかわからないかもしれませんが、あなたが提供した情報に基づいて推測しています。あなたの問題を実証するSSCCE(sscce.org)を提供する方が役立つかもしれません-その点で私はあなたの質問を「完全」とは言いません。SO(主にプログラミングの初心者)には、「インメモリ」データベースがプログラムの呼び出し間で存続できるコンピュータのメモリにデータを格納していると考える人がいるため、上記の回答を提供しました。あなたの質問はあなたがこれらの人々の一人ではないことを私に納得させるほど十分に完全ではありませんでした。
ルーク・ウッドワード

5

追加しようとしました

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

しかし、それは助けにはなりませんでした。上のH2サイト、私は確かにいくつかのケースで役立つ可能性が次のことを、発見しました。

デフォルトでは、データベースへの最後の接続を閉じると、データベースが閉じます。インメモリデータベースの場合、これはコンテンツが失われることを意味します。データベースを開いたままにするには、データベースのURLに; DB_CLOSE_DELAY = -1を追加します。仮想マシンが稼働している限り、インメモリデータベースのコンテンツを保持するには、jdbc:h2:mem:test; DB_CLOSE_DELAY = -1を使用します。

しかし、私の問題は、スキーマがデフォルトのものとは異なるはずであるということでした。だから使うつもり

JDBC URL: jdbc:h2:mem:test

私は使用しなければなりませんでした:

JDBC URL: jdbc:h2:mem:testdb

その後、テーブルが表示されました


おかげで、「testdb」も私にとっては修正でした(「DB_CLOSE_DELAY = -1」に加えて)!
boly38 2017年

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


これは、この回答でカバーされていないものを追加しません。口コミから
ワイハリー

3

h2-consoleを開くとき、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フォルダーを作成し、application.propertiesファイルを挿入して、テストdbaseの作成を明示的に指定することで解決します。

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

1

同じエラーが発生したため、この投稿にアクセスしました。

私の場合、データベースの進化は実行されなかったので、テーブルはまったくありませんでした。

私の問題は、evolutionスクリプトのフォルダ構造が間違っていることでした。

から:https : //www.playframework.com/documentation/2.0/Evolutions

Playは、いくつかの進化スクリプトを使用してデータベースの進化を追跡します。これらのスクリプトは古いSQLで記述されており、アプリケーションのconf / evolutions / {データベース名}ディレクトリに配置する必要があります。進化がデフォルトのデータベースに適用される場合、このパスはconf / evolutions / defaultです。

私はeclipseによって作成された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 Data JPAの Springブートバージョン2.2.6.RELEASE への依存性を追加した後、私はそれが機能しているのを見つけました-

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

H2 DB設定をapplication.ymlに追加します-

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.200Spring-Boot 2.2.6.RELEASEを使用しています


-2

Time.sleep(1000);

これは私の仕事です。試してみると、PCが遅い場合はスレッドの継続時間を長くして、DBが正常に機能し、JVMがテーブルを取得できるようにすることができます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.