11.5 JDBC
Machbase JDBCドライバーはJava 8を基準にJDBC 4.2の主要APIを提供します。標準JDBC APIで サーバーに接続し、PreparedStatement、型指定の検索とバインディング、データベースメタデータ、 ローカルトランザクション、接続プールを使用できます。
| 項目 | 値 |
|---|---|
| Javaバイトコード基準 | Java 8 |
| ドライバーが報告するJDBCバージョン | 4.2 |
| ドライバーバージョン | 3.0.0 |
| JDBC URL | jdbc:machbase://<host-list>/[database] |
Driver.jdbcCompliant() | false |
jdbcCompliant()のfalseはJDBC 4.2 APIのサポート状況ではなく、SQL-92 Entry Level全体への
準拠状況を示します。アプリケーションでは必要な任意機能をDatabaseMetaDataの機能メソッドで確認します。
マルチデータベース
URLパスまたはdatabase接続プロパティで初期データベースを指定できます。
String url = "jdbc:machbase://127.0.0.1:5656/factory_a";
Connection conn = DriverManager.getConnection(url, "APP_A", password);
System.out.println(conn.getCatalog());
conn.setCatalog("FACTORY_A");getCatalog()とsetCatalog()はサーバーの現在のデータベースと同期します。URLパスと設定プロパティを
両方指定する場合は同じ値にする必要があります。JDBCメタデータではカタログはデータベース、スキーマは
所有者です。プールされた接続の返却時に初期カタログへ復元されるか確認し、プリペアドステートメントと
Appendハンドルは作成時のデータベースに固定される点を考慮します。
ドライバーのインストール
JARファイルの使用
Machbaseインストールディレクトリのmachbase.jarをクラスパスに追加します。
ls -l "$MACHBASE_HOME/lib/machbase.jar"
javac -classpath ".:$MACHBASE_HOME/lib/machbase.jar" MyApp.java
java -classpath ".:$MACHBASE_HOME/lib/machbase.jar" MyAppJARにはMETA-INF/services/java.sql.Driverが含まれています。JDBC 4.0以降の環境では
Class.forName("com.machbase.jdbc.MachDriver")を呼び出さなくてもドライバーが自動登録されます。
既存アプリケーションの明示的な呼び出しも引き続き使用できます。
Maven
<dependency>
<groupId>com.machbase</groupId>
<artifactId>machjdbc</artifactId>
<version>8.0.2</version>
</dependency>Gradle
dependencies {
implementation 'com.machbase:machjdbc:8.0.2'
}配布成果物のバージョンはMaven Centralで
確認します。ドライバーが実行時メタデータで返す3.0.0と配布成果物のバージョンは、別のバージョン体系です。
サーバーへの接続
ユーザー名とパスワードはソースコードに記録せず、環境変数やシークレット管理システムで渡します。
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;
String url = "jdbc:machbase://127.0.0.1:5656/machbasedb";
Properties properties = new Properties();
properties.setProperty("user", "SYS");
properties.setProperty("password", System.getenv("MACHBASE_PASSWORD"));
try (Connection connection =
DriverManager.getConnection(url, properties)) {
// SQLを実行します。
}接続オプション
接続オプションはPropertiesまたはURLクエリ文字列で指定します。randomHostはPropertiesで
指定するか、複数ホストURLの^区切り文字を使用します。
| オプション | 説明 |
|---|---|
user, password | パスワード認証情報 |
TIMEZONE | セッションのタイムゾーン。+0900形式を使用します。 |
randomHost | ホスト一覧から最初の接続先をランダムに選択します。 |
maxStatements | プールされた接続の最大キャッシュStatement数 |
CONNECTION_TIMEOUT | ソケット接続のタイムアウト(秒)。0は無制限です。 |
SOCKET_TIMEOUT | ソケット読み取りのタイムアウト(秒)。0は無制限です。 |
characterEncoding | クライアントの文字エンコーディング |
AUTH_MODE | PASSWORDまたはCHALLENGE |
AUTH_SIG_SCHEME | ECDSA、RSA_PKCS1_V15、RSA_PSS |
AUTH_KEY_FILE | PEM秘密鍵ファイルのパス |
String url =
"jdbc:machbase://127.0.0.1:5656/machbasedb?TIMEZONE=+0900";複数ホストへの接続
Machbase 8.7.0 JDBCドライバーは、1つのURLに複数ホストを指定できます。
| 選択方式 | 指定方法 | 動作 |
|---|---|---|
| 順次選択 | ホストを,で区切る | URLの記載順に接続を試みます。 |
| ランダム開始 | ホストを^で区切る | ホスト一覧から最初の接続先をランダムに選びます。 |
| ランダム開始 | PropertiesでrandomHost=trueを指定 | ,で区切った一覧から最初の接続先をランダムに選びます。 |
次のURLはdb1への接続に失敗すると、db2への接続を試みます。
String url =
"jdbc:machbase://db1.example.com:5656,db2.example.com:5656/" +
"machbasedb?CONNECTION_TIMEOUT=5";^区切り文字を使用すると、最初の接続先をランダムに選択します。
String url =
"jdbc:machbase://db1.example.com:5656^db2.example.com:5656/" +
"machbasedb?CONNECTION_TIMEOUT=5";randomHost設定プロパティを使用する場合は、,でホストを区切ります。
Properties properties = new Properties();
properties.setProperty("randomHost", "true");
String url =
"jdbc:machbase://db1.example.com:5656,db2.example.com:5656/" +
"machbasedb?CONNECTION_TIMEOUT=5";- 1つのURLで
,と^の区切り文字は併用できません。 - 接続拒否、接続タイムアウト、ソケットエラーなど接続段階のI/Oエラーが発生すると、次のホストへの
接続を試みます。すべてのホストが失敗すると
DriverManager.getConnection()はSQLExceptionを返します。 CONNECTION_TIMEOUTはホストごとの接続試行に適用されます。そのため全体の接続待機時間は ホスト数と各ホストの応答時間によって長くなる場合があります。SOCKET_TIMEOUTは接続済みソケットの読み取り待機時間を制限し、ホストの選択順序は変更しません。
複数ホストの切り替えは、新規接続または再接続時のソケット接続に適用されます。切断後に自動再接続が 成功しても、以前のStatement、PreparedStatement、ResultSetは再利用しません。実行中のSQLの成功や 安全な再実行は保証されないため、有効なトランザクションで接続エラーが発生した場合は接続を破棄し、 業務の冪等性ポリシーに従ってトランザクション全体を再実行します。
AUTH KEY認証
公開鍵によるチャレンジ認証では、パスワードの代わりにローカルの秘密鍵でサーバーチャレンジに署名します。
Properties properties = new Properties();
properties.setProperty("user", "app_user");
properties.setProperty("AUTH_MODE", "CHALLENGE");
properties.setProperty("AUTH_SIG_SCHEME", "ECDSA");
properties.setProperty(
"AUTH_KEY_FILE", "/opt/machbase/keys/app_user_ecdsa.pem");
Connection connection = DriverManager.getConnection(
"jdbc:machbase://127.0.0.1:5656/machbasedb", properties);AUTH_MODE=CHALLENGEでは認証にpasswordを使用しません。AUTH_KEY_FILEは必須です。AUTH_SIG_SCHEMEを省略すると、鍵の種類に合うデフォルト署名方式を選択します。- POSIX環境では秘密鍵ファイルの権限を
600に制限します。
クイックスタート
次の例はLOGテーブルに値を入力し、再検索します。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;
public class JdbcQuickStart {
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
properties.setProperty("user", "SYS");
properties.setProperty(
"password", System.getenv("MACHBASE_PASSWORD"));
try (Connection connection = DriverManager.getConnection(
"jdbc:machbase://127.0.0.1:5656/machbasedb",
properties);
Statement statement = connection.createStatement()) {
statement.execute(
"CREATE LOG TABLE jdbc_sensor " +
"(ts DATETIME, name VARCHAR(40), value DOUBLE)");
try (PreparedStatement insert = connection.prepareStatement(
"INSERT INTO jdbc_sensor VALUES (?, ?, ?)")) {
insert.setLong(1, System.currentTimeMillis() * 1_000_000L);
insert.setString(2, "sensor-1");
insert.setDouble(3, 25.3);
insert.executeUpdate();
}
try (ResultSet result = statement.executeQuery(
"SELECT name, value FROM jdbc_sensor")) {
while (result.next()) {
System.out.printf("%s %.1f%n",
result.getString("NAME"),
result.getDouble("VALUE"));
}
}
}
}
}DATETIMEにエポックナノ秒値を渡す場合はlongを使用します。例のテーブルがすでに存在する場合は、
CREATE LOG TABLEを省略するか別名を使用します。
INSERT結果のROWID
Standard Editionで単一のINSERT ... VALUESが成功すると、JDBC標準の生成キーAPIで入力行の
ROWIDを確認できます。
String sql = "INSERT INTO jdbc_sensor VALUES (?, ?, ?)";
try (PreparedStatement insert = connection.prepareStatement(
sql, Statement.RETURN_GENERATED_KEYS)) {
insert.setLong(1, System.currentTimeMillis() * 1_000_000L);
insert.setString(2, "sensor-2");
insert.setDouble(3, 26.1);
insert.executeUpdate();
try (ResultSet keys = insert.getGeneratedKeys()) {
if (keys.next()) {
java.sql.RowId rowId = keys.getRowId("ROWID");
}
}
}結果は1つのROWID列と最大1行で構成されます。返すROWIDがない場合は空のResultSetです。
サポート状況はDatabaseMetaData.supportsGetGeneratedKeys()で確認します。
バッチ、Append、INSERT ... SELECT、UPSERTの違いは
ROWIDとINSERT結果IDを参照してください。
バージョンの確認
import java.sql.DatabaseMetaData;
DatabaseMetaData metadata = connection.getMetaData();
System.out.println(metadata.getDriverName());
System.out.println(metadata.getDriverVersion());
System.out.println(metadata.getJDBCMajorVersion()); // 4
System.out.println(metadata.getJDBCMinorVersion()); // 2関連ドキュメント
| ドキュメント | 内容 |
|---|---|
| PreparedStatementと型 | パラメーターメタデータ、名前付きbind、SQLType、NULL、型変換 |
| ResultSet、Statement、LOB | 型指定の検索、ストリーム、LOB、タイムアウト、リソース管理 |
| トランザクションと接続プール | Standardのローカルトランザクション、DataSource、接続プール |
| DatabaseMetaData | テーブル、列、キー、インデックス、機能の検索 |
| Append API | MachStatementによる高速入力 |
| 移行とトラブルシューティング | 旧ドライバーからの移行、非サポート機能、エラー処理 |