Tomcat6.x系でDataSourceを使用してDBにアクセスしてみた。
ネットでいろいろ探しながらDataSourceを使用しました。
環境は以下です。
Eclipse3.4
Tomcat6.0.20
Tomcat5.x系の解説が多いので、それを見ながら実装しましたが、
以下のエラーがずっと解決できませんでした。
org.apache.tomcat.dbcp.dbcp.SQLNestedException: Cannot create JDBC driver of class '' for connect URL 'null'
今日やっと解決できました。
結論、Tomcatのバージョンで配置するファイルの場所が違うことに気づきました。
「百聞は一見にしかず!!」ということで早速紹介します。
では今日の材料は以下になります。
<一人前> Servlet・・・・1つ Dto・・・・1つ Web.xml・・・・少々 画面・・・・少々 Context.xml・・・・一つ
では吟じて見たいと思います。
吟じます!!
まずServletを書きます。
全体は以下のようになります。
package jp.net.damePg; import java.io.IOException; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.sql.DataSource; public class DataSourseServlet extends HttpServlet { private Connection con = null; @Override public void init() throws ServletException { try { InitialContext ic = new InitialContext(); DataSource ds = (DataSource)ic.lookup("java:comp/env/damePg"); con = ds.getConnection(); } catch (NamingException e) { // InitialContext生成時に例外発生 e.printStackTrace(); } catch (SQLException e) { // コネクション取得時に例外発生 e.printStackTrace(); } } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { if (con != null) { try { Statement st = con.createStatement(); ResultSet rs = st.executeQuery("SELECT * FROM TEST"); List list = new ArrayList(); while(rs.next()) { Dto d = new Dto(); d.setId(rs.getInt(1)); d.setName(rs.getString(2)); list.add(d); } req.setAttribute("SQLResult", list); rs.close(); st.close(); req.getRequestDispatcher("result.jsp").forward(req, resp); } catch (SQLException e) { e.printStackTrace(); } finally { try { con.close(); } catch (SQLException e) { e.printStackTrace(); } } } else { req.getRequestDispatcher("error.jsp").forward(req, resp); } } }
GenericServletで実装されているinitをOverrideします。
そのなかでConnectionを取得するコードを書いています。
Connectionを取得しているのは以下です。
InitialContext ic = new InitialContext(); DataSource ds = (DataSource)ic.lookup("java:comp/env/damePg"); con = ds.getConnection();
Connectionを取得するという責務は、DriverManagerを使用するのと同じです。
少し解説しておきます。
lookupの引数のjava:comp/env/までは決まりです。
その後の「damePg」は後に記述するWeb.xmlとContext.xmlと一致しないといけません。
次にWeb.xmlです
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>datasourseTest</display-name> <servlet> <servlet-name>test</servlet-name> <servlet-class>jp.net.damePg.DataSourseServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>test</servlet-name> <url-pattern>/test</url-pattern> </servlet-mapping> <resource-ref> <res-ref-name>damePg</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> </web-app>
通常のアプリケーション作成に加えて以下が必要になります。
<resource-ref> <res-ref-name>damePg</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref>
res-ref-nameはServlet、lookupの引数java:comp/env/の後に記述した内容と同じものを記述します。
res-authはContainerかApllicationを選択できます。
今回はオーソドックスにContainerを使用します。
では次にContext.xmlです。
ここが一番肝心です。
<?xml version="1.0" encoding="UTF-8"?> <Context> <Resource name="damePg" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="ユーザー名" password="パスワード" driverClassName="org.gjt.mm.mysql.Driver" url="jdbc:mysql://localhost:3306/test?autoReconnect=true"/> </Context>
「name」「auth」「type」はWeb.xmlで記述した内容と同じものを記述します。
続いて以下を記述します。
username・・・MySQLユーザ名
password・・・MySQLパスワード
driverClassName・・・DriverManagerを使用するときClass.forNameの引数に指定するのと同じもの
url・・・DriverManagerを使用するときDriverManagerのgetConnectionの第一引数に指定するのと同じもの
そしてContext.xmlをMETA-INF直下に配置します。
Tomcat5.x系はServer.xmlに記述する方法がネットにはたくさんありますが
それではTomcat6.x系はExceptionが発生します。
後は普通にWebアプリケーションを開発するようにすればOK!!
ためしに動作させてみます。
出力しました。
あると思います!!
せっかくなのでこんな実験をしてみました。
mainメソッドで呼び出せるかどうかです。
以下のコードを実行します。
package jp.net.damePg; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import javax.naming.InitialContext; import javax.sql.DataSource; public class DatasourceMain{ public static void main(String[] args) { try { InitialContext context = new InitialContext(); DataSource ds = (DataSource)context.lookup("java:comp/env/jdbc/datasource"); Connection con = ds.getConnection(); Statement st = con.createStatement(); ResultSet rs = st.executeQuery("select * from test"); while (rs.next()) { System.out.println(rs.getInt("id")); System.out.println(rs.getString("name")); } } catch (Exception e) { e.printStackTrace(); } } }
すると以下の例外が発生しました。
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
DataSourcceはWebアプリケーションしか使用できないのですね。
松坂大輔の不調の原因は制球力だと思うdamePGでした。