S-JIS[2023-10-07/2023-10-28]
TsurugiのTsubakuro(Java通信ライブラリー)のSqlClientのPreparedStatementのメモ。
|
Tsubakuroの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を呼び出すようにすればよい。