2007年9月19日水曜日

ZK: JNDI接続

WEBアプリケーションはJDBC接続を通じてリモートのRDBMSにアクセスする。この際クライアントアプリケーションとRDBMSサーバの間にはTCP/IPを介し物理的にJDBC接続が確立されるがデータベースと物理的に接続を確立するには大きなCPUパワーが必要で時間もかかる。このためHTTPリクエストの度にアプリケーションとRDBMSの間で物理的に接続、切断を行うことはパフォーマンスに大きな影響がでる。そこでアプリケーションサーバはシステム起動時にデータベースとの物理的な接続をプールし、データベースとの接続を必要とするアプリケーションはールマネージャを介しデータベースに論理的に接続するようにする。そしてデータベース使い終えたアプリケーションは論理的に接続を切断し、プールマネージャは次のデータベース接続要求を待つことになる。
--だそうです


JNDIとはJava Naming and Directory Interfaceの頭文字を取ったもので、Javaから
* ネーミング・サービス
* ディレクトリー・サービス
扱うためのインターフェイスを規定した仕様です。

*詳しくは「今さら人に聞けないJNDI」


Fedor Core 6 でハマッタ
/etc/hostsに 127.0.0.1 localhost エントリが無い!!
$ cat /etc/hosts
 # Do not remove the following line, or various programs
# that require network functionality will fail.
::1 localhost.localdomain localhost



JNDI接続ではlocalhostが127.0.0.1に解決できないとデータベース接続できないようだ。
ブラウザからはlocalhost:8080で アドレス解決できるし、SpringやSeasarでもホスト名にはlocalhostを使用していて問題なかったので気づくのに時間がかかった。



    動作環境確認
  • OS Fedora Core 6

  • Java jdk1.5.0_09

  • /usr/java/jdk1.5.0_09へインストールし、シンボリックリンク/usr/java/jdk作成
    $JAVA_HOME=/usr/java/jdk $CLASSPATH=.:/usr/java/jdk/jre/lib:/usr/java/jdk/lib:/usr/java/jdk/lib/tools.jar
  • MySQL 5.20.27

  • Tomcat apache-tomcat-5.5.20

  • /usr/apache-tomcat-5.5.20へインストールし、シンボリックリンク/usr/tomcat作成
  • Eclipse 3.2(wtp-all-in-one)

  • ZK 2.4

  • ZKライブラリの配置
    アーカイブを展開してできたディレクトリdist/libとdist/lib/ext内の全てのjarファイルをEclipseのライブラリとして取り込む。
  • /usr/tomcat/common/libへ配置したjarファイル

  • MySQL JDBCドライバ mysql-connector-java-5.0.4-bin.jar
    commons-pool-1.3.jar
    commons-collections-3.2.jar
    commons-dbcp-1.2.1.jar


  • Tomcat用JNDIリソース mysql/hellodb を設定する

  •  ($TOMCAT_DIR/conf/context.xml)
    <Context reloadable="true">
    <Resource
    name="mysql/hellodb"
    username="myadmin"
    password="*********"
    url="jdbc:mysql://localhost:3306/hellodb"
    auth="Container"
    defaultAutocommit="false"
    driverClassName="com.mysql.jdbc.Driver"
    type="javax.sql.DataSource"
    maxActive="20"
    maxIdle="30000"
    maxWait="100"
    />

    </Context>

    (Eclipseプロジェクトではcontext.xmlは$PROJECT_HOME/WebContent/META-INF/に配置する)

  • アプリケーションで使用するJNDIリソースmysql/hellodbを定義する

  •  (WEB-INF/web.xml)

    <resource-ref>
    <res-ref-name>mysql/hellodb</res-ref-name>
    <res-type>javax.sql.Datasource</red-type>
    <res-auth>Container</res-auth>
    </resource-ref>



  • Bean作成

  •  (my.Emp.java)

    public class Emp {
    private int empno;
    private String ename;
    private String job;

    public Emp(int empno, String ename, String job){
    this.empno = empno;
    this.ename = ename;
    this.job = job;
    }

    public int getEmpno() {
    return empno;
    }
    public void setEmpno(int empno) {
    this.empno = empno;
    }
    ... 残りのフィールドのgettter、setter メソッド省略
    }


  • アプリケーションからデータソースを参照するクラスを作成

  •  (my.EmpManager.java)

    public class EmpManager {
    public List findAll() throws Exception {
    DataSource ds = (DataSource)new InitialContext()
    .lookup("java:comp/env/mysql/hellodb");

    Connection conn = null;
    Statement stmt = null;
    ResultSet rs = null;

    List results = new LinkedList();
    try {
    conn = ds.getConnection();
    stmt = conn.createStatement();
    rs = stmt.executeQuery("select EMPNO, ENAME, JOB from EMP");
    while (rs.next()) {
    int empno = rs.getInt("EMPNO");
    String ename = rs.getString("ENAME");
    String job = rs.getString("JOB");
    results.add(new Emp(empno, ename, job));
    }
    return results;
    } finally {
    if (rs != null) try{ rs.close(); } catch (SQLException ex){}
    if (stmt != null) try{stmt.close();} catch (SQLException ex){}
    if (conn != null) try(conn.close();} catch (SQLException ex){}
    }
    }
    }


  • ビュー作成

  •  (conn-pool1.zul)

    <window title="Connection Pooling Demo 1" border="normal">
    <zscript>

    import my.EmpManager;
    emps = new EmpManager().findAll();
    </zscript>
    <listbox id="empList" width="800px">
    <listhead>
    <listheader label="Empno" />
    <listheader label="Name" />
    <listheader label="Job"/>

    </listhead>
    <listitem value="${each.empno}" forEach="${emps}">
    <listcell label="${each.empno}" />
    <listcell label="${each.ename}" />
    <listcell label="${each.job}" />
    </listitem>

    </listbox>
    </window>

  • インターフェース Initiatorの実装

  • org.zkoss.ak.ui.util.Initiatorを実装しinitディレクティブを使用することでzulファイルにJavaコードを記述せずにデータロードが可能になる。

    Eclipseメニュー
    +-ファイル
    +-新規
    +-その他
    +-クラス

    パッケージ: my
    名前: AllEmpFinder

    インターフェース
    [追加]

    インターフェースを選択してください: org.zkoss.ak.ui.util.Initiator
    [OK]


  • 作成されたテンプレートを編集


  • public void doInit(Page arg0, Object[] arg1) throws Exception {
    try {
    arg0.setVariable((String)arg1[0], new EmpManager().findAll());
    } catch (Exception ex){
    throw UiException.Aide.wrap(ex);
    }
    }


  • ビュー作成

  • (conn-pool2.zul)

    <window title="Connection Pooling Demo 2" border="normal">
    <?init class="my.AllEmpFinder" arg0="emps"?>
    ... 以降はconn-pool1.zulに同じ

    0 件のコメント: