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>
oracle-ds.xmlのtype-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/の直下にコピーする。
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を取得したら(エラーが発生しない限り)使い回すのが良い。