2010年9月14日 星期二

Tomcat 6.0 環境配置 DBCP 與 JNDI 使用

取得資料庫連線的過程必須經過網路連線、協定交換等多個步驟
過程中的耗費在單機使用者上也許感覺不太出來
但放大到使用者眾多的網路應用程式,開開關關的連線就是不可小看的浪費

改善連線效能的方法之一就是建立儲存了連線實例的連接池
盡量使用已經開啟的連線,重複使用以減低資源上的浪費
Tomcat的DBCP連接池機制提供了連接池建立的功能
JNDI 處理 Java EE 平台上資源的分散式運算的協調與資源上查詢
JNDI 更詳細的介紹可以在 SUN 的文件裡看到
接著搭配兩者來示範建立連接池

Java EE將資料庫處理的相關行為規範在 javax.sql.DataSource 介面
取得Connecion實例等的處理會由實作介面的物件來處理,我們只需取得DataSource實例即可
範例以建立一個能被封裝散佈的WAR檔的Web Application為例:
context.xml=========

<?xml version="1.0" encoding="UTF-8"?>
<!-- 應用程式目錄是Demo -->
<Context antiJARLocking="true" path="/Demo">
  <Resource name="jdbc/sql" auth="Container" type="javax.sql.DataSource"
            maxActive="60" maxIdle="20" maxWait="10000"
            username="***" password="***" driverClassName="com.mysql.jdbc.Driver"
            url="jdbc:mysql://localhost:3306/***?useUnicode=true&amp;characterEncoding=UTF8" />
</Context>

web.xml===========

<?xml version="1.0" encoding="UTF-8"?>
<web-app ...>
  ....... 
  <resource-ref>
      <res-ref-name>jdbc/sql</res-ref-name>
      <res-type>javax.sql.DataSource</res-type>
      <res-auth>Container</res-auth>
      <res-sharing-scope>Shareable</res-sharing-scope>
  </resource-ref>
  ....

</web-app>

DatabaseBean.java====

package tw.vencs;

import java.sql.*;
import java.util.logging.*;
import javax.naming.*;
import javax.sql.DataSource;

public class DatabaseBean {
    private DataSource dataSource;
   
    public DatabaseBean(){
        try{
            Context initContext = new InitialContext();
            //java:comp/env 表示應用程式環境項目
            Context envContext = (Context)initContext.lookup("java:/comp/env");
            //查找 jdbc/sql 對應的 DataSource 物件
            dataSource = (DataSource)envContext.lookup("jdbc/sql");
        }catch(NamingException ex){
            Logger.getLogger(DatabaseBean.class.getName()).log(Level.SEVERE, null, ex);
            throw new RuntimeException();
        }
    }
   
    public boolean isConnectedOK(){
        boolean ok = false;
        Connection conn = null;
        try{
            // 透過 DataSource 物件取得連線
            conn = dataSource.getConnection();
            if(!conn.isClosed()){
                ok = true;
            }
        }catch(SQLException ex){
            Logger.getLogger(DatabaseBean.class.getName()).log(Level.SEVERE, null, ex);
        }finally{
            if(conn != null){
                try{
                    conn.close();
                }catch(SQLException ex){
                    Logger.getLogger(DatabaseBean.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        return ok;
    }
}

conn.jsp========

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<jsp:useBean id="db" class="tw.vencs.DatabaseBean" />   
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>db Test</title>
</head>
<body>

<c:choose>
  <c:when test="${db.connectedOK }">連線成功</c:when>
  <c:otherwise>失敗</c:otherwise>
</c:choose>

</body>
</html>


context.xml需要放置在Web應用程式根目錄的META-INF目錄裡
<Context>裡的 path 填上相對於容器網路根目錄的應用程式目錄位置
<Resource>標籤裡有許多與連線設定相關的屬性
name                       存取辨識用的 JNDI 名稱
auth                         認證方式,一般為Container
type                         數據集的型別,使用標準的javax.sql.DataSource
maxActive               連接池中最多的Connection實例數量,0為不限制
maxIdle                   最大空閒連接數,也就是一個連接池裡最少要有的Connection實例數量
maxWait                  等待可用的Connection實例,最大的等待時間,-1為不限制
username                資料庫使用者名稱
password                 資料庫密碼
driverClassName     JDBC Driver 類別名稱
url                           JDBC URL,注意因資訊寫在xml裡,"&"需改成"&amp;"才符合XML規範

web.xml裡的設定提供 JNDI 查找時需要的環境資訊
減少物件建立所需要設置的參數的麻煩

DatabaseBean 物件裡不會看見資料庫連結的實體位置、連接阜等資訊
那些資訊由context.xml設定,只須給資料庫管理人員管理

程式部署後,Tomcat根據放在 META-INF 裡的context.xml設定,尋找指定的JDBC Driver
所以驅動程式也必須放在程式的Build path裡(如Tomcat的lib資料夾)
conn.jsp只提供了連線的訊息,資料庫的操作還須依照JDBC的規範來

沒有留言:

張貼留言