はぶあぶれーく

IT技術の勉強に関して記録していく備忘録的なものです。

H2の接続モードについて調べてみた

ずっと後回しにしていたH2DBについていろいろ調べてみた。

きっかけは、Springbootで起動したH2にDbSetupからアクセスできなかったことから、H2のことをもっと知ろうと思った。

ぼんやりとした知識

  • なんかインメモリで動く組み込みのデータベース
  • インメモリだけじゃなくてファイルでデータを扱うこともできるよ
  • インメモリではアプリ(Springboot)を落とすとデータが消えるので開発時には便利

ぐらいの感じでした。

調べてみた

公式ドキュメントを読んでみました。

QuickstartやTutorialを読んでみましたが、使い方は書いてあるものの、知りたいことはやっぱりわからず。

自分の知りたいことってなんだろう?考えてたんだけど、なかなか言語化できず、検索できなかったんですよね。

「仕組み」とはちょっと違うし、「中身」でもないし、何知りたいんだっけ?みたいな。

公式ドキュメントを読み進めていくとドンピシャのがありました。

Features

あ、機能を知りたかったんだ。と。

接続モードが3つある

  • 組み込みモード
  • サーバーモード
  • ミックスドモード
組み込みモードについて

SpringBootでデフォルトで接続されるのがこのモード。

ローカル接続

jdbc:h2:~/test や jdbc:h2:file:~/test のようなURLで接続した場合はローカルのファイルを使ってデータを保存するモード(ローカル接続)になります。

インメモリ接続

jdbc:h2:mem:db1 のようにh2:のあとに mem を付けるとインメモリでの接続となります。

また、名前なしのURL(jdbc:h2:mem:)で起動した場合は非公開(private)のデータベースを開くことになります。

この場合、同じURLで開いた場合は2つの異なるデータベースが開かれるので、同じデータベースにはアクセスできないということです。

同じインメモリに複数接続したい場合は、名前ありのURL(jdbc:h2:mem:db1など)で起動します。

この場合は、同じ仮想マシンとクラスローダー内に限り、同じ名前で開くと同じデータベースに接続可能です。

さらに、別のプロセスからアクセスしたい場合は、インメモリデータベースが作成されたのと同じプロセスでTCPサーバーを起動すれば、jdbc:h2:tcp://localhost/mem:db1などのデータベースURLを使用してアクセス可能です。

SpringBoot の場合はデフォルトがインメモリで、TCPサーバーが起動されていないので、TCPサーバーを起動すれば、冒頭の私の悩みである「DbSetupで接続したい」が叶うわけです。

SpringBootでH2のTCPサーバーを起動する方法は下記記事を参考にしました。

Querying the embedded H2 database of a Spring Boot application - techdev Solutions GmbH

サーバーモードについて

JDBCまたはODBC APIを使用してデータベースをリモートで開きます。

同じまたは別の仮想マシン内または別のコンピュータ上でサーバーを起動する必要があります。

このサーバーに接続することにより、同じデータベースに同時に接続できます。 内部的には、サーバープロセスは組み込みモードでデータベースを開きます。

すべてのモードと同様に、永続メモリとインメモリの両方のデータベースがサポートされています。

ドキュメントにはこんな感じで書かれてます。

同じデータベースに同時に接続するためには、このモードで立ち上げる必要があります。

jdbc:h2:tcp://localhost/~/test のようにh2:のあとにtcpを付けるとサーバーモードで立ち上がります。

インメモリ接続のところにも書きましたが、起動したあとは jdbc:h2:tcp://localhost/~/test で接続します。

ミックスドモードについて

混合モードは、組み込みモードとサーバーモードの組み合わせです。

データベースに接続する最初のアプリケーションは組み込みモードで動作しますが、別のアプリケーション(異なるプロセスまたは仮想マシンで実行中)が同じデータに同時にアクセスできるようにサーバーを起動します。

ローカル接続は、データベースが組み込みモードでのみ使用される場合と同じくらい速く、リモート接続は少し遅くなります。

サーバーは、サーバーAPIを使用してアプリケーション内から開始したり停止したり、自動的に(自動混合モード)開始することができます。 自動混合モードを使用する場合、データベースに接続するすべてのクライアント(ローカル接続またはリモート接続のいずれであっても)は、まったく同じデータベースURLを使用して行うことができます。

ドキュメントにはこんな感じに(ry

前述の、インメモリで接続してTCPサーバーを起動するのがミックスドモードということでしょうか。

「自動混合モード」はどうやったら使用できるのか、とか。ドキュメントのどこ見たら書いてあるんだろ。。。

気が向いたらまた調べときます。

おまけ

よく、「同じURLで接続してるのになんかうまくいってない!」とかあったんですが、たぶんPrivateで開いてたから同じURLでも違うデータベース開いてたんでしょうね。

これ、違うデータベース開いてるのか、ちゃんと接続してるけど何かしらの理由でうまくいってないのかの判別が難しいと思ってたのですが、良いオプションがありました。

String url = "jdbc:h2:/data/sample;IFEXISTS=TRUE";

IFEXISTSをTRUEにしてあげると既存のデータベースを開くことのみを許可することができます。

この場合、データベースが存在しない場合は、接続しようとすると例外がスローされます。

これは便利。トラブルシューティングに使えそうです。

まとめ

H2には接続モードが大きく分けて3つある。最低でも組み込みモードとサーバーモードの違いは知っておかないと使うのは厳しそう。(今までよく使ってたな。。。

ミックスドモードでどう開くのかは謎のまま。