S-JIS[2023-10-07/2023-10-28]

Tsubakuro PreparedStatement

TsurugiTsubakuro(Java通信ライブラリー)のSqlClientのPreparedStatementのメモ。


概要

TsubakuroのPreparedStatementは、Tsurugiサーバーに登録されたSQL文。
プレースホルダー(SQL文に埋め込む変数)も一緒に管理される。

PreparedStatementはSqlClientから生成する。
実行はTransactionのexecuteStatementまたはexecuteQueryメソッドで行う。
PreparedStatementは使い終わったらクローズする必要がある。


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)した方がスループットは良い。(ただし、まとめて応答を待つにも上限があるので、ある程度の件数で実施する必要がある)
例外発生時のクローズ処理を考えると、簡単ではないが…。


select文のPreparedStatementを生成・実行する例

    // 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メソッドで実行する。


PreparedStatementのメソッド

メソッド 説明 説明
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を呼び出すようにすればよい。


SqlClientへ戻る / Tsubakuroへ戻る / Tsurugiへ戻る / 技術メモへ戻る
メールの送信先:ひしだま