S-JIS[2008-08-16/2008-10-25] 変更履歴

JBossASでDBアクセス

JBossAS4.2.3でデータソースを使ってOracleにアクセスする実験。

JBossでは、データソースはJCA(J2EE Connector Architecture。JavaEE5でもJ2EEのまま)という奴が管理しているらしい。


データソースの定義

JBOSS_HOME/docs/examples/jca/にoracle-ds.xmlというファイルがある。 (XAの場合はoracle-xa-ds.xml)
これをコピーして中身を書き換える。

〜
<datasources>
  <local-tx-datasource>
    <jndi-name>OracleSampleDS</jndi-name>
    <connection-url>jdbc:oracle:thin:@localhost:1521:ora92</connection-url>

    <driver-class>oracle.jdbc.driver.OracleDriver</driver-class>
    <user-name>scott</user-name>
    <password>tiger</password>
〜
      <!-- corresponding type-mapping in the standardjbosscmp-jdbc.xml (optional) -->
      <metadata>
        <type-mapping>Oracle9i</type-mapping>
      </metadata>

  </local-tx-datasource>

</datasources>

で、書き換えたoracle-ds.xmlをJBOSS_HOME/server/default/deploy/直下に置く。(ファイル名の末尾が「-ds.xml」であれば、その前は何でもよい)
JBossのコンソールに以下のようなメッセージが出ればOK。

22:24:50,468 INFO [ConnectionFactoryBindingService] Bound ConnectionManager
'jboss.jca:service=DataSourceBinding,name=OracleSampleDS' to JNDI name 'java:OracleSampleDS'

JNDI名は頭に「java:」が付いて、「java:OracleSampleDS」となる。
JNDIViewでは「java: Namespace」の所に表示される。


ociドライバー(Type4)を使う場合は以下の様になる。[2008-10-25]

    <connection-url>jdbc:oracle:oci:@ora92</connection-url>

この場合、Oracleクライアントのtnsnames.oraの定義が必要。
(ここで書いている「ora92」は、SQL*Plusでログインするのに使うTNSのサービス名)

network\admin\tnsnames.ora:

ORA92 =
  (DESCRIPTION =
	〜
  )

※thinドライバー(Type2)の場合はtnsnames.oraは無関係。


DTDはJBOSS_HOME/docs/dtd/jboss-ds_1_5.dtdにある。[2008-10-04]

examplesのサンプルの中には書かれていないが、DBの文字コード(エンコーディング)を指定するにはconnection-propertyを追加する。[2008-09-09]
とDTDの中の例には書かれているのだが、Oracleでは関係無さそう…。[2008-10-04]

〜
<datasources>
  <local-tx-datasource>
〜
    <connection-property name="char.encoding">Windows-31J</connection-property>
  </local-tx-datasource>

</datasources>

JDBCドライバーの準備

oracle-ds.xmltype-mappingという所にJDBCのバージョンを指定するらしい。
「standardjbosscmp-jdbc.xmlを見ろ」とコメントされているが、これはJBOSS_HOME/server/default/conf/standardjbosscmp-jdbc.xmlのことらしい。
中を見ると

〜
      <type-mapping>
         <name>Oracle9i</name>
         <!--
         | This type-mapping applies both to Oracle 9i and Oracle 10g
         | Make sure that you have the latest Oracle 10g version of ojdbc14.jar
         -->
〜

Oracle9iという名前だがOracle9iと10g兼用で、最新のOracle10gのJDBCドライバー(JDK1.4用)を使えとのこと?
(ちなみにOracle8とか7にも別の定義で対応している模様)

インストールされているOracleディレクトリーの下からojdbc14.jarを探してきて、JBOSS_HOME/server/default/lib/の直下にコピーする。


サーブレットからデータソースを取得してDBアクセス

JBossでサーブレットを作ってSELECT文を実行してみる例。

import java.io.IOException;
import java.io.PrintWriter;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.naming.InitialContext;
import javax.naming.NamingException;

import javax.servlet.ServletException;
import javax.servlet.http.*;

import javax.sql.DataSource;
public class JdbcServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

		res.setContentType("text/html; charset=Shift_JIS");

		PrintWriter out = res.getWriter();
		out.println("<html>");
		out.println("<head>");
		out.println("<title>JBoss-JDBC-sample</title>");
		out.println("</head>");
		out.println("<body>");
		out.println("JBossサーブレットのJDBC呼び出しサンプル<br>");
		try {
			selectEMP(out);
		} catch (RuntimeException e) {
			throw e;
		} catch (Exception e) {
			throw new IOException(e);
		}
		out.println(new java.util.Date());
		out.println("</body>");
		out.println("</html>");
	}
	private DataSource _ds = null;

	protected DataSource datasource() throws NamingException {
		if (_ds == null) {
			InitialContext ctx = new InitialContext();
			try {
				_ds = (DataSource) ctx.lookup("java:OracleSampleDS");
			} finally {
				ctx.close();
			}
		}
		return _ds;
	}
	void selectEMP(PrintWriter out) throws Exception {
		DataSource ds = datasource();
		try {
			Connection conn = ds.getConnection();
			try {
				Statement st = conn.createStatement();
				try {
					ResultSet rs = st.executeQuery("SELECT * FROM EMP");
					try {
						while (rs.next()) {
							out.printf("%04d:%s<br>%n", rs.getInt("EMPNO"), rs.getString("ENAME"));
						}
					} finally {
						try { rs.close(); }catch(SQLException e){}
					}
				} finally {
					try { st.close(); }catch(SQLException e){}
				}
			} finally {
				try { conn.close(); }catch(SQLException e){}
			}
		} catch (SQLException e) {
			_ds = null;
			throw e;
		}
	}
} //JdbcServletの終わり

↑このtry〜finally群は、やりすぎか?(苦笑)

DataSourceはスレッドセーフ(だと思う)でContextのルックアップは重い処理なので、一度DataSourceを取得したら(エラーが発生しない限り)使い回すのが良い。

JBossでサーブレットを実行する方法


参考


JBossASへ戻る / Java目次へ行く / JDBCへ行く
メールの送信先:ひしだま