2018/7/14 全面改訂
====================================================================
0. はじめに
zd6ir7です。初投稿になります。よろしくお願いいたします。
件名のとおり、データベースのバインド変数を使うことによるメリットをお伝えしたいと思います。予めことわっておきますが、わかりやすさ追求のため、詳細を省略しているところがある点ご了承願います。
1. 「バインド変数」とは?
まずは、「バインド変数」とは何か?をお話しします(※1)。
DBMSに対して発行されるSQL文は外から与えられる値によって変動するものもあります。例えば以下のユーザ情報を保持したUSERTABLEを考えます(※2)。
id | passwrod | username | |
---|---|---|---|
22222 | password2 | ルフィー | chopperlovesluffy@pirates.com |
55555 | password5 | 桜木花道 | sakurahana@vvvyyy.go.jp |
11111 | password1 | 剣桃太郎 | momo_tsurugi@jump.otoko.co.jp |
33333 | password3 | きんにくすぐる | oreha@muscleman.net |
そのテーブルに対して、ユーザIDとパスワードをもとに情報を取得するSQLがあったとします。
SELECT * FROM USERTABLE WHERE ID='XXX' AND PASSWORD='YYY';
(XXXとYYYは仮の値です。)
当然ながらユーザIDとパスワードはユーザによって変わるものであり、カラムIDに与えられる値(XXX)とカラムPASSWORDに与えられる値(YYY)は当然変動するものです。
そこで、ID用の箱、PASSWORD用の箱を用意して、いろいろな値が格納できるようにします。それらの「箱」のことをバインド変数と呼びます。箱を用意する、つまりバインド変数を宣言する、ということです。
2.「バインド変数」の宣言
では、バインド変数を宣言するというのは、具体的にどのようなものなのでしょうか?Javaアプリケーションで上記のSQLを発行するコードを例に示します。
// SQLを宣言する。カラムidとpasswordに対して「?」を入れることで、これらはバインド変数であることを宣言する。
String sql = "select * from app.usertable where id = ? and password = ?";
// バインド変数を格納したSQLを発行するため、PreparedStatementを用意する。
preparedStatement = connection.prepareStatement(sql);
// idに対して値を代入する。この「1」というのは、1番目のバインド変数idを指す。
preparedStatement.setInt(1, 11111);
// passwordに対して値を代入する。この「2」というのは、2番目のバインド変数passwordを指す。
preparedStatement.setString(2, "password1");
// 結果を取得する。
resultSet = preparedStatement.executeQuery();
バインド変数を宣言しないで、SQLを発行する方法もあります。同じくJavaで、以下にそのコード例を示します(※3)。
// Statementを用意する。
statement = connection.createStatement();
// SQLを宣言する。可変値idとpasswordを入れてSQLを構成する。
String sql = "select * from app.usertable where id = 11111 and password = 'password1'";
// 結果を取得する。
resultSet = statement.executeQuery(sql);
このようにバインド変数を使わない方法もあるのに、どうしてわざわざバインド変数を宣言する必要があるのでしょうか?次回以降2つのメリットを紹介したいと思います。
脚注
(※1)
また「バインド変数」に関しては、以下のURLにわかりやすい解説が記載されているので、ご参照ください。
http://wa3.i-3-i.info/word12449.html
「バインド変数」はOracle、DB2等ではこの名称で呼ばれていますが、MySQLだと「ユーザー定義変数」(https://dev.mysql.com/doc/refman/5.6/ja/user-variables.html) と呼ばれているようです。お使いになられているDBMSがどのように呼ばれているかは、マニュアルを参照ください。
(※2)
パスワードがそのままテーブルに格納されていますが、あくまで例ということでご容赦ください。通常であればエンコードされて格納されます。
(※3)
バインド変数つきSQLを発行する際、JavaではPreparedStatementクラスを使います。一方で、そうしない場合はStatementクラスを使います。前者クラスは、以下の文献から、実行されたSQLについての情報をプールして使いまわすことができる点でパフォーマンス面で優れていることが指摘されています。
O'Reilly Japan - Javaパフォーマンス
https://www.oreilly.co.jp/books/9784873117188/
OCP: Oracle Certified Professional Java SE 8 Programmer II Study Guide: Exam 1Z0-809
http://as.wiley.com/WileyCDA/WileyTitle/productCd-1119067901,miniSiteCd-SYBEX.html
なお今回コード例を載せるにあたり、上記文献を参照しました。