1. 程式人生 > >[Servlet&JSP] 使用JDBC連線資料庫

[Servlet&JSP] 使用JDBC連線資料庫

JDBC(Java DataBase Connectivity)時用於執行SQL的解決方案,開發人員使用JDBC的標準介面,資料庫廠商則對介面進行實現,這樣開發人員就可以無需接觸底層資料庫驅動程式的差異性。

JDBC簡介

廠商在實現JDBC驅動程式時,依方式可將驅動程式分為四種類型:

  1. JDBC-ODBC Bridge Driver
    將JDBC呼叫轉換為ODBC呼叫
  2. Native API Driver
    將JDBC呼叫轉換為原生連結庫中的相關API呼叫。特點:與平臺相依,是四種類型中最快的驅動程式。
  3. JDBC-Net Driver
    將JDBC呼叫轉換為特定的網路協議呼叫,目的是與遠端資料庫特定的中間伺服器或元件進行協議操作,而中介軟體或組建再真正與資料庫進行操作。特點:彈性最高。
  4. Native Protocol Driver
    主要作用是將JDBC呼叫轉換為特定的網路協議,所以驅動驅動程式可以使用Java技術來實現,遺傳你這型別的驅動程式可以跨平臺,在效能上也有不錯的表現。在不需要如第3種驅動型別的靈活性時,通常是會使用這型別驅動程式,該型別時最常見的驅動程式型別。

以下編寫一個簡單的JavaBean來測試可否連線資料庫:

package club.chuxing;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.logging.Level;
import
java.util.logging.Logger; public class DbBean { private String url; private String username; private String password; public DbBean(){ try { Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException e) { Logger.getLogger(DbBean.class.getName()).log(Level.SEVERE, null
, e); } } public boolean isConnectedOk() { boolean ok = false; Connection conn = null; try { conn = DriverManager.getConnection(url, username, password); if (!conn.isClosed()) { ok = true; } } catch (SQLException e) { Logger.getLogger(DbBean.class.getName()).log(Level.SEVERE, null, e); } finally { if (conn != null) { try { conn.close(); } catch (SQLException e) { Logger.getLogger(DbBean.class.getName()) .log(Level.SEVERE, null, e); } } } return ok; } public void setPassword(String password) { this.password = password; } public void setUrl(String url) { this.url = url; } public void setName(String username) { this.username = username; } }

之後就可以通過呼叫isConnectedOK()方法來看看是否可以連線成功。例如,可以寫個簡單的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="club.chuxing.DbBean" />
<c:set target="${db}" property="url" value="jdbc:mysql://localhost:3306/test" />
<c:set target="${db}" property="username" value="root" />
<c:set target="${db}" property="password" value="123" />
<!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>Test Database Connection</title>
    </head>
    <body>
        <c:choose>
            <c:when test="${db.connectedOK}">連線成功</c:when>
            <%-- <c:when test="<%db.isConnectedOK();%>">連線成功</c:when> --%>
            <c:otherwise>連線失敗</c:otherwise>
        </c:choose>
    </body>
</html>

使用DataSource取得連線

在Java EE中的環境中,將取得連線等與資料庫來源相關的行為規範在javax.sql.DataSource介面,實際如何取得Connection則由實現介面的物件來負責。

為了讓應用程式在需要取得某些與系統相關的資源物件時,能與實際的系統配置、實體機器位置、環境架構等無關,在Java應用程式中可以通過JNDI(Java Naming Directory Interface)來取得所需的資源物件。可用如下方式取得DataSource例項:

try {
    Context initContext = new InitialContext();
    Context envContext = (Context)initContext.lookup("java:/comp/env");
    dataSource = (DataSource)envContext.lookup("jdbc/test");
} catch(NamingException ex) {
    //other process
}

在建立Context物件的過程中會收集環境的相關資料,之後根據JNDI名稱jdbc/demo向JNDI伺服器查詢DataSource例項並返回。在這個程式片段中,不會知道實際的資源配置、實體機器位置、環境架構等資訊,應用程式不會與這些相依。

之前的DbBean類可以改為如下編寫方式:

package club.chuxing;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

public class DatabaseBean {
    private DataSource dataSource;
    public DatabaseBean(){
        try {
            Context initContext = new InitialContext();
            Context envContext = (Context)initContext.lookup("java:/comp/env");
            dataSource = (DataSource)envContext.lookup("jdbc/test");
        } catch(NamingException ex) {
            Logger.getLogger(DatabaseBean.class.getName())
                .log(Level.SEVERE, null, ex);
        }
    }

    public boolean isConnectedOK(){
        boolean ok = false;
        Connection conn = null;
        try {
            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;
    }
}

以上程式碼並不含有驅動程式、資料庫使用者名稱、密碼等資訊,這些都由資料庫管理人員或伺服器管理人員負責設定,我們唯一需要知道的就是jdbc/test這個JNDI名稱,並且告訴web容器,也就是要在web.xml中設定。

web.xml:

<web-app ...>
  <resource-ref>
      <res-ref-name>jdbc/demo</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>

在web.xml中設定的目的,就是讓web容器提供JNDI查詢時所需的相關環境資訊,這樣建立Context物件時就不用設定一大堆引數了。接著可以編寫一個簡單的JSP來使用DatabaseBean。

<%@ 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="club.chuxing.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>Test Database Connection</title>
    </head>
    <body>
        <c:choose>
            <c:when test="${db.connectedOK}">連線成功</c:when>
            <%-- <c:when test="<%= db.isConnectedOK()%>">連線成功</c:when> --%>
            <c:otherwise>連線失敗</c:otherwise>
        </c:choose>
    </body>
</html>

對於Java開發人員來說,它的工作已經完成了。現在假設你是伺服器管理員,職責就是設定JNDI相關資源,但設定的方式並非標準的一部分,而是依應用程式伺服器而有所不同。假設應用程式將部署在Tomcat6上,則可以要求web應用程式在封裝為war檔案時,必須在META-INF資料夾中包括一個context.xml檔案。例如:

<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/JDBCDemo">
    <Resource name="jdbc/demo" auth="Container" type="javax.sql.DataSource"
    maxActive="100" maxIdle="30" maxWait="1000" username="root" password="123"
    driverClassName="com.mysql.jdbc.Driver"
    url="jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=UTF-8"/>
</Context>

name屬性用來設定JNDI名稱,username與password用來設定資料庫使用者名稱和密碼,driverClassName用來設定驅動程式類名稱,url用來設定JDBC URL。其他屬性則是與DBCP(Database Connection Pool)有關的,這是內建在Tomcat中的連線池機制。

當應用程式部署後,Tomcat會根據META-INF中context.xml的設定,尋找指定的驅動程式,所以必須將驅動程式的JAR檔案放置在Tomcat的lib目錄中,接著Tomcat就會為JNDI名稱jdbc/demo設定相關的資源。

使用root來操作資料庫是不安全的,root賬號用於操作資料庫的完整許可權,應用設定具有適當許可權的使用者來操作資料庫。