S-JIS[2023-10-07/2023-10-28]
TsurugiのTsubakuro/Java(Java通信ライブラリー)のSqlClientのPreparedStatementのメモ。
|
Tsubakuro/JavaのPreparedStatementは、Tsurugiサーバーに登録されたSQL文。
プレースホルダー(SQL文に埋め込む変数)も一緒に管理される。
PreparedStatementはSqlClientから生成する。
実行はTransactionのexecuteStatementまたはexecuteQueryメソッドで行う。
PreparedStatementは使い終わったらクローズする必要がある。
import java.util.List; import java.util.concurrent.TimeUnit; import com.tsurugidb.sql.proto.SqlCommon.AtomType; import com.tsurugidb.tsubakuro.sql.Parameters; import com.tsurugidb.tsubakuro.sql.Placeholders; import com.tsurugidb.tsubakuro.sql.PreparedStatement;
// PreparedStatement生成
String sql = "insert into test values(:pk, :value)";
var placeholders = List.of(Placeholders.of("pk", AtomType.INT4), Placeholders.of("value", AtomType.INT8));
try (PreparedStatement ps = sqlClient.prepare(sql, placeholders).await(3, TimeUnit.SECONDS)) {
// トランザクション開始
var option = TransactionOption.newBuilder().setType(TransactionType.SHORT).build();
try (var transaction = sqlClient.createTransaction(option).await(3, TimeUnit.SECONDS)) {
for (int i = 1; i <= 100; i++) {
// PreparedStatement(SQL)実行
var parameters = List.of(Parameters.of("pk", i), Parameters.of("value", i * 10L));
transaction.executeStatement(ps, parameters).await(3, TimeUnit.SECONDS);
}
// コミット
transaction.commit().await(10, TimeUnit.SECONDS);
}
}
PreparedStatementはSqlClientのprepareメソッドで生成する。
SQL文には、「:変数名」の形式でプレースホルダーを埋め込む。
そして、Placeholdersを使ってプレースホルダーのデータ型(AtomType)を定義する。
PreparedStatementで定義されたSQLの実行はTransactionのメソッド(更新系SQLの場合はexecuteStatementメソッド)で行う。
プレースホルダーに代入する具体的な値はParametersで指定する。
FutureResponseのawaitメソッドは便利だが、executeStatementメソッドの実行を上記のようにawaitで行うと、大量の実行を行う場合でも1件実行する度に完了を待つことになって、効率が悪い。 (時間がかかる)
executeStatementから返ってきたFutureResponseを保持し、数十件実行した後でまとめてFutureResponseからget(またはawait)した方がスループットは良い。(ただし、まとめて応答を待つにも上限があるので、ある程度の件数で実施する必要がある)
例外発生時のクローズ処理を考えると、簡単ではないが…。
// PreparedStatement生成
String sql = "select * from test where :pk = 1";
var placeholders = List.of(Placeholders.of("pk", AtomType.INT4));
try (PreparedStatement ps = sqlClient.prepare(sql, placeholders).await(3, TimeUnit.SECONDS)) {
// トランザクション開始
var option = TransactionOption.newBuilder().setType(TransactionType.SHORT).build();
try (var transaction = sqlClient.createTransaction(option).await(3, TimeUnit.SECONDS)) {
// PreparedStatement(SQL)実行
var parameters = List.of(Parameters.of("pk", 1));
try (var rs = transaction.executeQuery(ps, parameters).await(3, TimeUnit.SECONDS)) {
〜 // rsからselect結果を取得
}
// コミット
transaction.commit().await(10, TimeUnit.SECONDS);
}
}
select文はTransactionのexecuteQueryメソッドで実行する。
| メソッド | 説明 | 説明 |
|---|---|---|
| hasResultRecords | ResultSetを返すかどうか。 | boolean b = ps.hasResultRecords(); |
| setCloseTimeout | クローズのタイムアウト時間を設定する。 | ps.setCloseTimeout(3,
TimeUnit.SECONDS); |
| close | PreparedStatementをクローズする。 |
PreparedStatementを使って、select文の場合はtransaction.executeQuery()、更新系SQLの場合はtransaction.executeStatement()を呼び出してSQLを実行する。[2023-10-28]
固定でSQLを指定している場合はselect文か更新系SQLかはプログラマーが分かっているので、それに応じてexecuteQuery/executeStatementを呼び分ければいいが、
汎用的にSQLを受け入れるようなアプリケーションの場合は、hasResultRecords()がtrueを返した場合はexecuteQuery、そうでない場合はexecuteStatementを呼び出すようにすればよい。