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を取得したら(エラーが発生しない限り)使い回すのが良い。