転職を繰り返したサラリーマンの多趣味ブログ

30才未経験でSEに転職した人の多趣味ブログ

【技術書メモ】基礎からのサーブレット⑭

リクエストパラメータを使ったSQL

<body>

<p>検索キーワードを入力してください</p>
<form action="search" method="post">

	<input type="text" name="keyword">
	<input type="submit" value="検索">

</form>

</body>
@WebServlet(urlPatterns={"/chapter14/search"})
public class Search extends HttpServlet {

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

		PrintWriter pw = resp.getWriter();
		Page.header(pw);

		try {

			InitialContext ic=new InitialContext();
			DataSource ds=(DataSource)ic.lookup("java:/comp/env/jdbc/book");
			Connection con=ds.getConnection();

			// リクエストパラメータの取得
			String keyword = req.getParameter("keyword");

			// SQL文の指定
			// プレースホルダ(後から値を設定可能)を記述
			PreparedStatement st=con.prepareStatement("select * from product where name like ?");
			st.setString(1,  "%" + keyword + "%");

			// SQL文の実行
			ResultSet rs=st.executeQuery();

			// 結果の取得
			while (rs.next()) {
				pw.println(rs.getInt("id"));
				pw.println(":");
				pw.println(rs.getString("name"));
				pw.println(":");
				pw.println(rs.getInt("price"));
				pw.println("<br>");
			}

			// データベースからの切断
			// ResultSetクラスは、PreparedStatemntクラスがクローズされると自動的にクローズされるため省略可
			st.close();
			con.close();

		} catch (Exception e) {
			e.printStackTrace(pw);
		}

		Page.footer(pw);
	}

}

SQLインジェクション

SQLインジェクション・・・想定しないSQL文を実行され、データベースを不正操作すること。

登録するサーブレット

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

<p>検索キーワードを入力してください</p>
<form action="search" method="post">

	<input type="text" name="keyword">
	<input type="submit" value="検索">

</form>

</body>
</html>
@WebServlet(urlPatterns={"/chapter14/search"})
public class Search extends HttpServlet {

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

		PrintWriter pw = resp.getWriter();
		Page.header(pw);

		try {

			InitialContext ic=new InitialContext();
			DataSource ds=(DataSource)ic.lookup("java:/comp/env/jdbc/book");
			Connection con=ds.getConnection();

			// リクエストパラメータの取得
			String keyword = req.getParameter("keyword");

			// SQL文の指定
			// プレースホルダ(後から値を設定可能)を記述
			PreparedStatement st=con.prepareStatement("select * from product where name like ?");
			st.setString(1,  "%" + keyword + "%");

			// SQL文の実行
			ResultSet rs=st.executeQuery();

			// 結果の取得
			while (rs.next()) {
				pw.println(rs.getInt("id"));
				pw.println(":");
				pw.println(rs.getString("name"));
				pw.println(":");
				pw.println(rs.getInt("price"));
				pw.println("<br>");
			}

			// データベースからの切断
			// ResultSetクラスは、PreparedStatemntクラスがクローズされると自動的にクローズされるため省略可
			st.close();
			con.close();

		} catch (Exception e) {
			e.printStackTrace(pw);
		}

		Page.footer(pw);
	}

}

トランザクション

トランザクション・・・DBにおいて分割して実行することのできない処理の単位
コミット・・・実行の結果を確定すること
ロールバック・・・実行を取り消して、実行前の状態にもどすこと

デフォルトでは、自動コミットモードが有効になっている。SQL文を1個実行する限りは、自動コミットで問題ない。

@WebServlet(urlPatterns={"/chapter14/transaction"})
public class Transaction extends HttpServlet {

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

		PrintWriter pw = resp.getWriter();
		Page.header(pw);
		try {
			InitialContext ic=new InitialContext();
			DataSource ds=(DataSource)ic.lookup("java:/comp/env/jdbc/book");
			Connection con=ds.getConnection();

			// リクエストパラメータの取得
			String name = req.getParameter("name");
			int price = Integer.parseInt(req.getParameter("price"));

			// 自動コミットを無効
			con.setAutoCommit(false);

			PreparedStatement ps = con.prepareStatement("insert into product values(null, ?, ?)");
			ps.setString(1, name);
			ps.setInt(2, price);

			// SQL文の実行
			ps.executeUpdate();

			ps = con.prepareStatement("select * from product where name = ?");
			ps.setString(1, name);

			// SQL文の実行
			ResultSet rs = ps.executeQuery();

			int line = 0;
			while(rs.next()) {
				line++;
			}

			if(line == 1) {
				// コミット
				con.commit();
				pw.println("商品を登録しました。");
			} else {
				// ロールバック
				con.rollback();
				pw.println("商品はすでに登録されています");
			}

			con.setAutoCommit(true);

			ps.close();
			con.close();

		} catch (Exception e) {
			e.printStackTrace(pw);
		}
		Page.footer(pw);
	}

}

トランザクション分離レベル・・・複数のトランザクションが同時に実行されたとき、トランザクションの一貫性をどの程度まで保つかを定義したもの。

SERIALIZABLE・・・複数のトランザクションを順番に実行したとき同じ結果になる
REPEATABLE READ・・・トランザクションが実行中に取得するデータは、途中で他のトランザクションによって変更されない
READ COMMITTED・・・他のトランザクションによる更新について、コミット済みのデータのみを取得する
READ UNCOMMITTED・・・他のトランザクションによる更新について、コミット済みでないデータも取得する