Java で JDBC を用いて MySQL に接続する Webアプリケーション の実装手順をまとめてみました。
目次
概要
Eclipse で Java、Tomcat を用いて「MySQL へ接続して結果を表示するアプリ」を作ってみます。
作成するプロジェクトは「Dynamic Web Project」で、作成するファイルは以下の通りです。
JDBCドライバ の 配置
MySQL の JDBCドライバ 「Connector/J」 をダウンロードしてプロジェクトへ組み込みます。
以下ではその具体的な手順を載せます。
-
「Connector/J」ダウンロードサイトへ移動
MySQL :: Download Connector/J
-
ZIPファイルの「Donwload」を選択
-
「No thanks, just start my download.」を選択
-
ダウンロードした ZIPファイル を解凍
-
「mysql-connector-java-5.1.38-bin.jar」 をプロジェクトの「/WebContent/WEB-INF/lib」配下へ ドラッグ & ドロップ
-
「File Operation」では「Copy files」が選択されていることを確認して「OK」を選択
/WEB-INF/lib フォルダはビルドパスに含まれているため、libフォルダ配下に配置された jarファイル は自動的にビルド時に読み込まれます。
%CATALINA_HOME%/lib 配下へ配置することもできますが、こちらへ配置すると個人の開発環境全体へ影響してしまうので個人的にはおススメしません。。
可能なら各プロジェクト毎に利用するライブラリを管理する方が変な不具合(人によって再現したりしなかったり等)を防げると思います。
JNDI へ 登録
データベースへの接続先情報は外だし(外部ファイル)にしておいた方がメンテナンス性が良いので外だしします。
具体的には context.xml に データベース への接続情報を記述します。
作成した context.xml は META-INFフォルダ 配下に context.xml の名前で配置することが固定で決まっています。
/META-INF/context.xml
<?xml version="1.0" encoding="UTF-8" ?>
<Context>
<Resource
name="jdbc/world"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/world"
connectionProperties="autoReconnect=true;verifyServerCertificate=false;useSSL=false;requireSSL=false"
username="world"
password="world"
validationQuery="select 1"/>
</Context>
Resource
要素 に指定できる属性とその説明を以下にまとめます。
属性名 |
概要 |
name |
データソースを一意に識別する名前。
JNDIを利用してデータソースを取得する際のキーになる名前。 |
auth |
リソースの制御方法。データソースを利用する場合は「Container 」で固定。 |
type |
リソースのデータ型。データソースを利用する場合は「javax.sql.DataSource 」で固定。 |
driverClassName |
JDBCドライバクラスの完全修飾名(使用するドライバ毎に決まっている)。
MySQLは「com.mysql.jdbc.Driver 」。 |
url |
接続文字列(接続するデータベースによりURLフォーマットが異なる)。
MySQLは「jdbc:mysql://サーバー名:ポート番号/データベース名 」。 |
connectionProperties |
接続文字列に付与するオプション。
セミコロン区切りで連結。 |
username |
接続時に使用するユーザ名。 |
password |
接続時に使用するパスワード。 |
maxActive |
プーリングする最大接続数。 |
maxIdle |
待機時に最低維持する接続数。 |
maxWait |
接続に対しての最大待ち時間(ミリ秒)。 |
validationQuery |
接続検証用のSQL。 |
データベース接続
ここからは JSP や Servlet へデータベース接続の実装を行っていきます。
基本的な手続きは同じなのですが…各場所や書き方がいくつか考えられるのでここでは例として3パターン取り上げます。
- (1) JSP上で接続して ResultSet を取得
- (2) Servlet上で接続して ResultSet を取得 (基本)
- (3) Servlet上で接続して ResultSet を取得 (応用)
(1) JSP上で接続して ResultSet を取得
Servletにはなにも記載せず、JSP上ですべて完結させるような実装です。
MVCの観点から考えるとViewに実装が含まれてしまっているのであまり良いとは言い難い実装かと思いますが…
コードは一番理解しやすいものだと思います。
sample.controllers.Connect1Controller.java
package sample.controllers;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class Connect1Controller
*/
@WebServlet("/Connect1")
public class Connect1Controller extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// Viewを表示
this.getServletContext().getRequestDispatcher("/WEB-INF/sample/views/Connect1View.jsp").forward(request, response);
}
}
/WEB-INF/sample/views/Connect1View.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
import="java.sql.*, javax.naming.*, javax.sql.*, java.text.*"%>
<!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>connect type 1</title>
</head>
<body>
<h1>(1) JSP上でResultSetを取得するサンプル</h1>
<table>
<tr>
<th>ID</th>
<th>Name</th>
<th>CountryCode</th>
<th>District</th>
<th>Population</th>
</tr>
<%
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/world");
con = ds.getConnection();
pstmt = con.prepareStatement("select * from city");
rs = pstmt.executeQuery();
while(rs.next()){
out.println("<tr>");
out.println("<td>" + rs.getString("ID") + "</td>");
out.println("<td>" + rs.getString("Name") + "</td>");
out.println("<td>" + rs.getString("CountryCode") + "</td>");
out.println("<td>" + rs.getString("District") + "</td>");
out.println("<td>" + rs.getString("Population") + "</td>");
out.println("</tr>");
}
}catch(Exception e){
throw new ServletException(e);
}finally{
try{
rs.close();
pstmt.close();
con.close();
}catch(Exception e){}
}
%>
</table>
</body>
</html>
L25 、 java:comp/env/jdbc/world
の指定で 前述 context.xml において JNDI登録した データソース のキーを指定しています。
URLパターンは決まっており、 java:comp/env/データソースを特定するキー
となっています。
(2) Servlet上で接続して ResultSet を取得 (基本)
DataSource
を InitialContext
経由で取得する サンプルコード です。
前述の JSP実装 を Servlet側 へ移動させた実装になります。
sample.controllers.Connect2Controller.java
package sample.controllers;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
/**
* Servlet implementation class Connect1Controller
*/
@WebServlet("/Connect2")
public class Connect2Controller extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
// データソースの取得
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/world");
// データベースへ接続
con = ds.getConnection();
// SQLの実行
pstmt = con.prepareStatement("select * from city");
rs = pstmt.executeQuery();
// Viewへ引き渡す値を設定
rs.first();
request.setAttribute("ID", rs.getString("ID"));
request.setAttribute("Name", rs.getString("Name"));
request.setAttribute("CountryCode", rs.getString("CountryCode"));
request.setAttribute("District", rs.getString("District"));
request.setAttribute("Population", rs.getString("Population"));
} catch (Exception e) {
System.out.println(e.getMessage());
throw new ServletException(e);
} finally {
try {
rs.close();
pstmt.close();
con.close();
} catch (Exception e) {
}
}
// Viewを表示
this.getServletContext().getRequestDispatcher("/WEB-INF/sample/views/Connect2View.jsp").forward(request, response);
}
}
/WEB-INF/sample/views/Connect2View.jsp
<%@ 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>connect type 2</title>
</head>
<body>
<h1>(2) Servlet 上で接続して ResultSet を取得 (基本)</h1>
<table>
<tr>
<th>ID</th>
<th>Name</th>
<th>CountryCode</th>
<th>District</th>
<th>Population</th>
</tr>
<tr>
<td>${ID }</td>
<td>${Name }</td>
<td>${CountryCode }</td>
<td>${District }</td>
<td>${Population }</td>
</tr>
</table>
</body>
</html>
(3) Servlet上で接続して ResultSet を取得 (応用)
DataSource
を メンバ変数 として @Resource アノテーション
を利用した サンプルコード です。
前述の実装とあまり変わらないように見えますが、 ResultSet が破棄される前に JSP へ渡したいので try-catch の中で forward しています。
sample.controllers.Connect3Controller.java
package sample.controllers;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
/**
* Servlet implementation class Connect1Controller
*/
@WebServlet("/Connect3")
public class Connect3Controller extends HttpServlet {
private static final long serialVersionUID = 1L;
@Resource(name="jdbc/world")
private DataSource ds = null;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
// データベースへ接続
con = this.ds.getConnection();
// SQLの実行
pstmt = con.prepareStatement("select * from city");
rs = pstmt.executeQuery();
// Viewへ引き渡す値を設定
request.setAttribute("rs", rs);
// Viewを表示
this.getServletContext().getRequestDispatcher("/WEB-INF/sample/views/Connect3View.jsp").forward(request, response);
} catch (Exception e) {
System.out.println(e.getMessage());
throw new ServletException(e);
} finally {
try {
rs.close();
pstmt.close();
con.close();
} catch (Exception e) {
}
}
}
}
/WEB-INF/sample/views/Connect3View.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
import="java.sql.*, javax.naming.*, javax.sql.*, java.text.*"%>
<!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>connect type 3</title>
</head>
<body>
<h1>(3) Servlet 上で接続して ResultSet を取得 (応用)</h1>
<table>
<tr>
<th>ID</th>
<th>Name</th>
<th>CountryCode</th>
<th>District</th>
<th>Population</th>
</tr>
<%
ResultSet rs = (ResultSet)request.getAttribute("rs");
while(rs.next()){
out.println("<tr>");
out.println("<td>" + rs.getString("ID") + "</td>");
out.println("<td>" + rs.getString("Name") + "</td>");
out.println("<td>" + rs.getString("CountryCode") + "</td>");
out.println("<td>" + rs.getString("District") + "</td>");
out.println("<td>" + rs.getString("Population") + "</td>");
out.println("</tr>");
}
%>
</table>
</body>
</html>