ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

Java質問&情報提供サイトコミュの【Bean】汎用的なデータベースアクセスオブジェクト【DAO】について

  • mixiチェック
  • このエントリーをはてなブックマークに追加
初めまして!本日このコミュニティを見つけて参加させて頂きました。

早速本題に入ります。

トピックタイトルの通り、Webアプリケーションに関しての質問なのですが、
データベースにアクセスする為だけに用意するDAOの設計についてお聞きしたいのですが・・・

まず私が書いたソースを提出致します。
(インデントは投稿後もちゃんと見えるのかな・・・?)

Dao.java
-----
package bean;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;


public class Dao implements Serializable {
private static final long serialVersionUID = 1L;

//クラス変数
private Statement stmt;
private Connection con;
private ResultSet rs;

//コンストラクタ
public Dao() {
stmt = null;
con = null;
rs = null;
}

public boolean connect(String host, String user, String pass, String dbName) {

//JDBCドライバをロード
System.out.println("jdbc:mysql://" + host + ":3306/" + dbName);
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
}

//ロードしたドライバを使ってDBに接続する
try {
con = DriverManager.getConnection("jdbc:mysql://" + host + ":3306/" + dbName, user, pass);
} catch (SQLException e) {
e.printStackTrace();
return false;
}

//ステートメントを生成する
try {
stmt = con.createStatement();
} catch (SQLException e) {
e.printStackTrace();
return false;
}

return true;
}

//connect()メソッドに引数を指定しない場合のデフォルト値
public boolean connect() {
return connect("localhost", "root", "root", "mydb");
}

public boolean close() {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
return false;
}
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
return false;
}
return true;
}

public ResultSet query(String sql) {
System.out.println("Daoのquery = " + sql);
try {
rs = stmt.executeQuery(sql);
} catch(SQLException e) {
e.printStackTrace();
}
return rs;
}

public int update(String sql) {
int ret = -1;
try {
ret = stmt.executeUpdate(sql);
} catch(SQLException e) {
e.printStackTrace();
}
return ret;
}

}
-----

上記のように、結構汎用的に出来ていると思います。
使う時は
-----
bean.Dao dao = new bean.Dao();
dao.connect();
ResultSet rs = dao.query("SELECT * FROM user WHERE uname = 'hoge' AND pass = 'piyo'");
while(rs.next()) {
//省略
}
dao.close();
-----
とか・・・

-----
bean.Dao dao = new bean.Dao();
dao.connect();
int ret = dao.update("DELETE FROM user WHERE uid = 1");
dao.close();
-----
とか言う感じに、JSPもしくはServletからDaoのインスタンスを生成して使う事ができます。

しかしこの状態だと、SQLインジェクション攻撃を受けてしまいます。(検証済み)
そこで何か良い対策はないかと調べてみたところ、PreparedStatementを使うと
サニタイジングを内部で勝手にやってくれるらしく、ぜひこれを利用しようと考えました。
しかしココで問題が発生しました。
PreparedStatementをこのDaoに適用したいのですが、どういう風にコーディングすれば
汎用的に、様々なシステムに使いまわせるDaoになるのかが分からないのです。
上記の使い方みたいに、手軽にDBにconnect()した後 queryメソッドやらupdteメソッドで
SQLを実行した後、close()で閉じると言うような使い勝手のDaoを作りたいと思っています。
しかしPreparedStatementは ? と言う文字で(プレースホルダと言う?)
"SELECT * FROM user WHERE uname = ? pas = ?" みたいな文字列を与えないといけないし、
その後で setString(1, "hoge") setString(2, "piyo") と言ったコードを書かないといけません。
与えるSQL文が毎回色々違うわけなので、 ? の部分が何個必要になるか分からないし、
StringじゃなくてIntの引数(例えば会員番号を与えるとか)、あるいはDataの引数を与えるとか
1.引数の数が違う
2.与える引数の型が違う

ので、どうやれば汎用的になるか全く分かりません。かなり難しい質問?かと
思いますが、どうかお分かりになる方、サンプルコードと共にご教示頂けないでしょうか?
上記(1.2.)が違うのに予めメソッドを用意しておく事なんて出来るのでしょうか?

コメント(3)

勉強なら良いですが、仕事なら、世の中に出回ってるデータアクセスフレームワーク
をいくつかお試しになったほうが良いと思います。

ログインすると、みんなのコメントがもっと見れるよ

mixiユーザー
ログインしてコメントしよう!

Java質問&情報提供サイト 更新情報

Java質問&情報提供サイトのメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。