ヘッダーをスキップ

Oracle Containers for J2EE サーブレット開発者ガイド
10g(10.1.3.1.0)

B31859-01
目次
目次
索引
索引

戻る 次へ

8 JDBCまたはEnterprise JavaBeansの使用方法

動的Webアプリケーションは、通常、コンテンツを提供するために、データベースにアクセスします。この章では、データベース接続性のJava標準APIであるJDBCをサーブレットで使用する方法について説明します。また、Enterprise JavaBeansの概要も示します。Enterprise JavaBeansは、サーバー・サイド・ビジネス・ロジックを実行したり、アプリケーションのデータ永続性を管理するために、サーブレットからコールすることができます。この章には、次の項が含まれます。

サーブレットでのJDBCの使用方法

サーブレットは、JDBCドライバを使用してデータベースにアクセス可能です。JDBCの使用方法としては、データベース接続にOC4Jデータソースを使用し、Java Naming and Directory Interface(JNDI)を使用してデータソースをルックアップすることをお薦めします。次の項では、関連する基本手順を説明し、この機能の例を示します。

JDBCの詳細は、『Oracle Database JDBC開発者ガイドおよびリファレンス』を参照してください。

JDBCを使用する理由

サーブレットの利点の1つに、データベースからデータを取得して動的出力を作成できる点があげられます。サーブレットは、データベースから情報を取得して動的HTMLを生成してそれをクライアントに返すことや、HTTPリクエスト内でサーブレットに渡された情報に基づいてデータベースを更新することが可能です。

JDBCは、データベースにアクセスするための標準Javaメカニズムです。


注意

  • 全般的な前提として、OracleデータベースとOracle JDBCドライバを使用するものとします。非Oracleデータベースへの接続には、Oracle Application Serverで提供されているDataDirect JDBCドライバを使用できます。

  • サーブレットから直接JDBCを使用するかわりに、EJBを使用してデータにアクセスできます。 「Enterprise JavaBeansの概要」も参照してください。

 

データソースおよびリソース参照の構成

データベース接続には、通常、標準データソースが使用されます。この項では、JNDIによって使用できるデータソースを構成する手順を説明します。

  1. データソースの構成

  2. リソース参照の構成

データソースとそのOC4Jでの構成の詳細は、『Oracle Containers for J2EEサービス・ガイド』を参照してください。

データソースの構成

データソースを使用するには、データソースを主要OC4Jデータソース構成に追加する必要があります。一般に、この手順は、Oracle Enterprise Manager 10g Application Server Controlを使用して実行します。

Application Server Controlコンソールで、次の手順を実行します。

  1. 該当する「アプリケーション」ホームページから、またはOC4Jホームページから、「管理」タブを選択します。

  2. 「JDBCリソース」というタスクに移動します。

  3. 「JDBCリソース」ページから、データソースを作成できます。前に作成したデータソースを編集することもできます。また、このページから接続プールを編集することもできます。

データソースを構成すると、次のフォームに従って、j2ee/home/config/data-sources.xmlファイルのエントリが(この例では、Oracle JDBCシン・ドライバを使用するために)新しく追加または更新されます。次の点に注意してください。

「問合せサーブレットのデータソースの構成」の例を参照してください。

<data-sources ... >
    <connection-pool name="poolname">
        <connection-factory factory-class="package.Classname"
                            user="user"
                            password="password"
                            url="jdbc:oracle:thin:@host:port/service"/>
    </connection-pool>
    <managed-data-source connection-pool-name="poolname"
                         jndi-name="jndiname"
                         name="name"/>
</data-sources>


注意

urlエントリについては、host:port:sid形式もまだサポートされていますが、廃止される可能性があります。 


リソース参照の構成

データソースおよびJNDIルックアップを使用するには、web.xmlファイルに適切なリソース参照エントリも存在する必要があります。次に、前の項で示したデータソース構成の例に対応する例を示します。

   <resource-ref>
      <res-auth>Container</res-auth>
      <res-ref-name>jdbc/OracleDS</res-ref-name>
      <res-type>javax.sql.DataSource</res-type>
   </resource-ref>

これにより、データソースとして使用するために、jdbc/OracleDSリソースがDataSourceタイプであることが確立されます。


注意

<res-auth>要素には必ずContainer設定を使用してください。これにより、アプリケーション・コンポーネント・コードではなくコンテナがリソースへのサインオンを実行することが示されます。 


JDBCコールの実装

この項では、サーブレット・コードでJDBCによってデータベースにアクセスする一般的な手順を示します。 例の全体は、「問合せサーブレットの作成」を参照してください。

  1. 必要なパッケージをインポートします。サーブレットおよびjava.ioパッケージに加えて、JDBC、データソースおよびJNDIのクラスを含むパッケージが存在します。

    import javax.servlet.*;
    import javax.servlet.http.*;
    import javax.naming.*;  // for JNDI
    import javax.sql.*;     // extended JDBC interfaces (such as data sources)
    import java.sql.*;      // standard JDBC interfaces
    import java.io.*;
    
  2. データソースのJNDIルックアップを実行し、データベース接続を確立するために、init()メソッドをtry...catchブロック内に実装します。 このルックアップは、「データソースおよびリソース参照の構成」で示した例に対応します。

      public void init() throws ServletException {
        try {
          InitialContext ic = new InitialContext();  // JNDI initial context
          ds = (DataSource) ic.lookup("jdbc/OracleDS"); // JNDI lookup
          conn = ds.getConnection();  // database connection through data source
        }
        catch (SQLException se) {
          throw new ServletException(se);
        }
        catch (NamingException ne) {
          throw new ServletException(ne);
        }
      }
    
  3. 適切なサーブレットのdoXXX()メソッド(doGet()など)を実装し、JDBCを使用して必要なSQL操作を実行します。この例では、SQL問合せ文字列が文字列のqueryで構成されているものとします。コードは、JDBC文オブジェクトを作成し、問合せを実行し、データ・レコードを出力するために結果セットを調べて(ここでoutPrintWriterオブジェクト)、文および結果セット・オブジェクトをクローズします。SQL操作も、try...catchブロック内で実行されます。

        try {
          Statement stmt = conn.createStatement();
          ResultSet rs = stmt.executeQuery(query);
          while (rs.next()) {
             out.println(rs.getString(1) + rs.getInt(2));
          }
          rs.close();
          stmt.close();
        }
        catch (SQLException se) {
          se.printStackTrace(out);
        }
    
  4. データベース接続を閉じるdestroy()メソッドを(同じくtry...catchブロック内に)実装します。

      public void destroy() {
        try {
          conn.close();
        }
        catch (SQLException se) {
          se.printStackTrace();
        }
      }
    

データベース問合せサーブレットの例

この例には、次の問合せを完成するLIKE仕様の入力をユーザーに求めるHTML「ようこそ」ページが含まれています。

SELECT ename, empno FROM emp WHERE ename LIKE xxx

「ようこそ」ページは、問合せを実行して結果を出力するサーブレットを起動します。

次の項で、例の実装および構成方法を示します。

問合せサーブレットのデータソースの構成

次に、この例のデータソース構成を示します。この構成は、OC4Jのdata-sources.xmlファイルに反映されており、Application Server Controlコンソールを使用して構成できます(「データソースの構成」を参照)。この例は、Oracle JDBCシン・ドライバを使用し、ポート5521経由で、ホストmyhost上のデータベースにアクセスします。その際、サービス名myserviceを使用し、ユーザーscottとして接続します。(これは単純化された例です。data-sources.xmlでのパスワードの公開を避ける方法もあります。)またこの例では、接続プール、および接続の取得先のデータソースを表すクラスOracleDataSourceを使用します。jndi-nameエントリのjdbc/OracleDSは、データソースのJNDIルックアップのためにサーブレットによって使用されます。

<data-sources>
       <connection-pool name="ConnectionPool1">
             <connection-factory factory-class="oracle.jdbc.pool.OracleDataSource"
                                 url="jdbc:oracle:thin:@myhost:5521/myservice" 
                                 user="scott" password="tiger"/>
       </connection-pool>
       <managed-data-source connection-pool-name="ConnectionPool1"
                            jndi-name="jdbc/OracleDS" name="OracleDS"/>
</data-sources>

HTML「ようこそ」ページの作成

次に、「ようこそ」ページのempinfo.htmlを示します。このページは、ユーザーに問合せの完成を求め、問合せサーブレットを起動します。この例の場合、サーブレットは、/myquery/getempinfoというコンテキスト・パスおよびサーブレット・パスで起動されるようにデプロイされます。

<html>
<head>
<title>Query the Employees Table</title>
</head>
<body>
<form method=GET ACTION="/myquery/getempinfo">
The query is<br>
SELECT ename, empno FROM emp WHERE ename LIKE xxx
 
<p>
Specify the WHERE clause xxx parameter.<br>
Enclose entry in single-quotes; use % for wildcard. Search is case-sensitive.<br>
Example: 'S%' (for all names starting with 'S').<br>
<input type=text name="queryVal">
<p>
<input type=submit>
</form>
</body>
</html>

問合せサーブレットの作成

次に、「JDBCコールの実装」で示した手順を実装する問合せサーブレットのGetEmpInfoを示します。この例には、出力されるHTML表の書式設定と、取得された行の数のカウンタも含まれています。

import javax.servlet.*;
import javax.servlet.http.*;
import javax.naming.*;  // for JNDI
import javax.sql.*;     // extended JDBC interfaces (such as data sources)
import java.sql.*;      // standard JDBC interfaces
import java.io.*;
 
public class GetEmpInfo extends HttpServlet {
 
  DataSource ds = null;
  Connection conn = null;
 
  public void init() throws ServletException {
    try {
      InitialContext ic = new InitialContext();  // JNDI initial context
      ds = (DataSource) ic.lookup("jdbc/OracleDS"); // JNDI lookup
      conn = ds.getConnection();  // database connection through data source
    }
    catch (SQLException se) {
      throw new ServletException(se);
    }
    catch (NamingException ne) {
      throw new ServletException(ne);
    }
  }
 
  public void doGet (HttpServletRequest req, HttpServletResponse resp)
                     throws ServletException, IOException {
 
/* Get the LIKE specification for the WHERE clause from the user, through the */
/* HTTP request, then construct the SQL query.                                */
    String queryVal = req.getParameter("queryVal");
    String query =
      "select ename, empno from emp " +
      "where ename like " + queryVal;
 
    resp.setContentType("text/html");
 
    PrintWriter out = resp.getWriter();
    out.println("<html>");
    out.println("<head><title>GetEmpInfo Servlet</title></head>");
    out.println("<body>");
 
/* Create a JDBC statement object and execute the query.     */
    try {
      Statement stmt = conn.createStatement();
      ResultSet rs = stmt.executeQuery(query);
 
/* HTML table formatting for the output.                     */
      out.println("<table border=1 width=50%>");
      out.println("<tr><th width=75%>Last Name</th><th width=25%>Employee " +
                   "ID</th></tr>");
 
/* Loop through the results. Using ResultSet getString() and         */
/* getInt() methods to retrieve the individual data items.           */
      int count=0;
      while (rs.next()) {
         count++;
         out.println("<tr><td>" + rs.getString(1) + "</td><td>" +rs.getInt(2) +
                     "</td></tr>");
       
      }
      out.println("</table>"); 
      out.println("<h3>" + count + " rows retrieved</h3>");
         
      rs.close();
      stmt.close();
    }
    catch (SQLException se) {
      se.printStackTrace(out);
    }
 
    out.println("</body></html>");
  }
 
  public void destroy() {
    try {
      conn.close();
    }
    catch (SQLException se) {
      se.printStackTrace();
    }
  }
}

サーブレットおよびJNDIリソース参照の構成

サーブレットの構成に加えて、web.xmlファイルには、データソースのリソース参照エントリが含まれている必要があります。また、初期ファイルとしてempinfo.htmlを宣言するための構成も含まれています。次に、この例のファイルを示します。

<?xml version="1.0" ?> 
<!DOCTYPE web-app (doctype...)> 
<web-app> 
   <servlet> 
      <servlet-name>empinfoquery</servlet-name> 
      <servlet-class>GetEmpInfo</servlet-class> 
   </servlet> 
   <servlet-mapping> 
      <servlet-name>empinfoquery</servlet-name> 
      <url-pattern>getempinfo</url-pattern> 
   </servlet-mapping> 
   <resource-ref> 
      <res-auth>Container</res-auth> 
      <res-ref-name>jdbc/OracleDS</res-ref-name> 
      <res-type>javax.sql.DataSource</res-type> 
   </resource-ref> 
   <welcome-file-list>
      <welcome-file>empinfo.html</welcome-file>
   </welcome-file-list>
</web-app>

問合せの例のパッケージ化

この例のWARファイル(empinfo.war)は、次のコンテンツと構造を持ちます。

empinfo.html
META-INF/Manifest.mf
WEB-INF/web.xml
WEB-INF/classes/GetEmpInfo.class
WEB-INF/classes/GetEmpInfo.java

また、EARファイルは、次のとおりです。

empinfo.war
META-INF/Manifest.mf
META-INF/application.xml

Manifest.mfファイルは、JARユーティリティにより自動的に作成されます。)

問合せの例の起動

この例では、application.xmlがコンテンツ・パスの/myqueryempinfo.warにマップするものとします。この場合、デプロイ後に、次のように、「ようこそ」ページのempinfo.htmlを起動することができます(web.xmlempinfo.htmlが「ようこそ」ページとして宣言されている必要があります)。

http://host:port/myquery

テスト実行では、Sで始まるすべての名前を検索するために'S%'を指定します。


画像の説明

テスト実行に使用されたデータベースの場合は、これにより、2つのエントリが返されました。


画像の説明

TopLinkサーブレットの例

サーブレットは、Oracle TopLinkを使用してJ2EE永続性をアプリケーションに提供します。 Oracle Technology Networkの次のWebサイトで、TopLinkサーブレットの例を参照できます。

http://www.oracle.com/technology/products/ias/toplink/examples/index.html

Enterprise JavaBeansの概要

サーブレットでは、Enterprise JavaBeansをコールして、データベースにアクセスすることや、追加のビジネス・ロジックを実行することができます。次の項で、EJBの概要と、サーブレットからのEJBの使用を説明します。

EJBの機能の詳細と、Oracle Application Server環境でのサーブレットとEJBに関する例は、『Oracle Containers for J2EE Enterprise JavaBeans開発者ガイド』を参照してください。


注意

OC4Jでは、JSPページからEJBへのアクセスを便利にするために、EJBタグ・ライブラリが用意されています。 詳細は、『Oracle Containers for J2EE JSPタグ・ライブラリおよびユーティリティ・リファレンス』を参照してください。 


Enterprise JavaBeansを使用する理由

EJBには、サーバー・サイド・ビジネス・ロジックに使用するセッションBeanやデータ永続性を管理するためのエンティティBeanなど、ビジネス・アプリケーションにおいて多くの用途があります。EJBテクノロジは、トランザクションによるセキュアなサーバー・サイド処理で使用するための、JSPまたはサーブレット・テクノロジよりも堅牢なインフラストラクチャを提供します。

一般的なアプリケーション設計では、サーブレットは、HTTPリクエストを処理するフロントエンド・コントローラとして使用され、EJBは、データベースへのアクセスと更新を行うためにコールされ、最後に、別のサーブレットまたはJSPページが、リクエスタのデータを表示するために使用されます。

EJBには、セッションBean、エンティティBeanおよびメッセージドリブンBeanという3つのカテゴリがあります。特に、コンテナ管理の永続性エンティティBeanは、永続データの管理に適しています。これは、データベースにアクセスする際にJDBC APIを直接使用する必要がなくなるためです。かわりに、EJBコンテナで透過的にデータベース操作を処理できます。

セッションBeanは、ビジネス・ロジックのモデリングに役立ちます。また、ステートレスまたはステートフルのいずれかになります。ステートフルなBeanは、一般に、トランザクション状態がメソッド・コールまたはサーブレット・リクエスト間で維持される必要がある場合に使用されます。ステートレスなBeanには、アプリケーション状態とは関係のない個別のビジネス・ロジック・メソッドが含まれます。

OC4JおよびOracle Application ServerでのEJBのサポート

OC4Jは、セッションBean、エンティティBeanおよびメッセージドリブンBeanを完全にサポートしています。エンティティBean実装は、Bean管理の永続性(BMP)、コンテナ管理の永続性(CMP)、ローカル・インタフェース、コンテナ管理の関連性、およびEJB問合せ言語による問合せ実行機能を提供します。

エンティティBean実装内では、基本永続性マネージャが単純マッピングと複合マッピングの両方をサポートし、1対1、1対多、多対1および多対多オブジェクト・リレーショナル・マッピングがサポートされます。また、エンティティBeanのフィールドが対応するデータベース表に自動的にマップされます。

アプリケーションのメンテナンスとデプロイを容易にするために、Oracle Application Serverは、動的EJBスタブ生成などの多数の拡張機能を提供します。CORBA相互運用性は、EJBを構築し、CORBAサービスとしてCORBAクライアントからEJBにアクセスする機能を提供します。

サーブレットとEJB間のルックアップの使用例

サーブレットからのEJBのコールには、3つの使用例があります。

サーブレットとEJB間の通信では、ローカルおよびリモートEJBコールにJNDIが使用されます。リモート・ルックアップが実行される場合、JNDIは、OracleによるRMI実装(ORMI)または標準で相互操作可能なInternet Inter-ORB Protocol(IIOP)のいずれかを使用します。3.0よりも古いバージョンのEJBでは、ホーム・インタフェースのみがJNDIルックアップを必要としました。その後は、アプリケーションが使用するEJBを作成するために使用されています。J2EEコンポーネントは、デフォルトのno-argsコンストラクタを使用して、同じアプリケーション内のオブジェクトをルックアップできます。リモート・ルックアップには、RMIInitialContextFactoryまたはIIOPInitialContextFactoryクラスを使用できます。 OC4JのJNDIの詳細は、『Oracle Containers for J2EEサービス・ガイド』を参照してください。

リモート・ルックアップを行うには、JNDI環境を設定する必要があります。これには、URL、ユーザー名およびパスワードが含まれます。この設定は、通常はサーブレット・コードで行われますが、同一アプリケーション内のルックアップでは、rmi.xmlファイル内で設定される場合もあります。

同一アプリケーション内の、異なるホストでのリモート・ルックアップの場合、各ホストで、アプリケーションのOC4J EJB remoteフラグを正しく設定する必要もあります。 「リモート・フラグによる同一アプリケーション内のリモート・ルックアップ」を参照してください。

EJBが使用されているすべてのアプリケーションと同様、ejb-jar.xmlファイルに、EJBごとにエントリが含まれている必要があります。

EJBローカル・インタフェースとリモート・インタフェース

EJB仕様の初期バージョンでは、EJBには、必ず、javax.ejb.EJBObjectインタフェースを拡張するリモート・インタフェースとjavax.ejb.EJBHomeインタフェースを拡張するホーム・インタフェースが備わっています。このモデルでは、すべてのEJBはリモート・オブジェクトとして定義されているため、サーブレットまたは別のコール元モジュールがEJBと同じ場所へ配置されている場合は、EJBコールに不要なオーバーヘッドが追加されます。


注意

OC4Jのcopy-by-valueパラメータ(orion-ejb-jar.xmlファイルの<session-deployment>要素にマップする)も、不要なオーバーヘッドの回避に関連しています。これは、EJBコールのすべての受信および送信パラメータをコピーするかどうかを指定します。 詳細は、『Oracle Containers for J2EE Enterprise JavaBeans開発者ガイド』を参照してください。 このパラメータがApplication Server Controlデプロイ・プラン・エディタでcopyByValueとして構成可能であることに注意してください。詳細は、『Oracle Containers for J2EEデプロイメント・ガイド』を参照してください。 


より新しいバージョンのEJB仕様は、同じ場所に配置されているEJBコールのローカル・インタフェースをサポートしています。この場合、EJBには、リモート・インタフェースではなく、javax.ejb.EJBLocalObjectインタフェースを拡張するローカル・インタフェースが備わっています。そして、ホーム・インタフェースではなく、javax.ejb.EJBLocalHomeインタフェースを拡張するローカル・ホーム・インタフェースが指定されます。

EJBリモート・インタフェースが関連するルックアップはRMIを使用するため、セキュリティなどの理由でオーバーヘッドが追加されます。ローカル・インタフェースを使用すると、RMIやその他のオーバーヘッドが回避されます。


注意

  • EJBは、ローカルおよびリモート・インタフェースの両方を備えることができます。

  • このマニュアルでは、ローカル・ルックアップという単語は、同一のJVM内の同じ場所に配置されているルックアップを指します。「ローカル・ルックアップ」と「ローカル・インタフェース」を混同しないでください。通常ローカル・ルックアップではローカル・インタフェースが使用されますが、かわりにリモート・インタフェースが使用される場合もあります。

 

リモート・フラグによる同一アプリケーション内のリモート・ルックアップ

OC4Jでは、リモートEJBルックアップを同一アプリケーションの異なる層で実行する場合(同一アプリケーションが両方の層でデプロイされている)、OC4J EJBのremoteフラグを各層で正しく設定する必要があります。サーバーでフラグがtrueに設定されている場合、Beanは、ローカル・サーバーで使用されているEJBサービスではなく、リモート・サーバーでルックアップされます。

remoteフラグは、orion-application.xmlファイルにある<orion-application>要素のサブ要素<ejb-module>内の属性にマップします。デフォルトの設定は、remote="false"です。ファイルを更新して、次のように、このフラグをtrueに設定してください。

<orion-application ... >
   ...
   <ejb-module remote="true" ... />
   ...
</orion-application>

(Oracle Enterprise Manager 10g Application Server Controlでこのフラグを設定することはできません。)

falseのリモート・フラグ値でアプリケーションのEARファイルを両サーバーにデプロイしてから、サーブレット層であるサーバー1でリモート・フラグ値をtrueに設定できます。図8-1にこれを示します。

図8-1    アプリケーション内のリモート・ルックアップの設定


画像の説明

サーバー2でEJBを検索するようにOC4Jを設定するには、サーバー2をリモート・ホストとして正しく構成する必要があります。次のように、サーバー1のrmi.xmlファイルの該当する<rmi-server>要素の<server>サブ要素で、hostportusernameおよびpassword設定を指定してください。

<rmi-server ... >
...
   <server host="remote_host" port="remote_port" username="user_name"
           password="password" />
...
</rmi-server>

リモート・ホストおよびremoteフラグの使用方法の詳細は、『Oracle Containers for J2EE Enterprise JavaBeans開発者ガイド』を参照してください。


注意

リモート・ホストのデフォルトの管理ユーザー名と、リモート・ホストで設定した管理パスワードを使用してください。このようにすることで、JAZN構成に関する問題を回避できます。 JAZNの詳細は、『Oracle Containers for J2EEセキュリティ・ガイド』を参照してください。 



戻る 次へ
Oracle
Copyright © 2006 Oracle Corporation.

All Rights Reserved.
目次
目次
索引
索引