在Tomcat中配置連線池和資料來源
阿新 • • 發佈:2019-02-18
1、DataSource介面介紹
- (1)DataSource 概述
- (2)使用DataSource的優點
關於資料來源的資訊和如何來定位資料來源,例如資料庫伺服器的名字,在哪臺機器上,埠號等等,都包含在DataSource物件的屬性裡面去了。這樣,對應用程式的設計來說是更方便了,因為並不需要硬性的把驅動的名字寫死到程式裡面去。通常驅動名字中都包含了驅動提供商的名字,而在DriverManager類中通常是這麼做的。
2,可移植性
如果資料來源要移植到另一個數據庫驅動中,程式碼也很容易做修改。所需要做的修改只是更改DataSource的相關的屬性。而使用DataSource物件的程式碼不需要做任何改動。
- (3)配置DataSource
在下面的例子中,名字起為:WebMisDB,按照慣例,邏輯名字通常都在jdbc的子上下文中。這樣,邏輯名字的全名就是:jdbc/WebMisDB。
- (4)產生一個與資料來源的連線
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("jdbc/WebMisDB");
Connection con = ds.getConnection("myPassword", "myUserName");
在一個基本的DataSource實現中,DataSource.getConnection方法返回的Connection物件和用DriverManager.getConnection方法返回的Connection物件是一樣的。因為DataSource提供的方便性,我們推薦使用DataSource物件來得到一個Connection物件。
- (5)DataSource的應用場合
- (6)資料來源(DataSource)的作用
它相當於客戶端程式和連線池的中介,想要獲得連線池中的連線物件,必須建立一個與該連線池相應的資料來源,然後通過該資料來源獲得連線。
2、JNDI(JAVA NAMING AND DIRECTORY INTERFACE---Java 命名和目錄介面)- (1)JNDI簡介
- (2)獲得JNDI的初始環境
Context ctx = new InitialContext ();
應用可以通過這個初始化的Context經由這個目錄樹來定位它所需要的資源或物件。InitialContext在網頁應用程式初始化時被設定,用來支援網頁應用程式元件。所有的入口和資源都放在JNDI名稱空間裡的java:comp/env段裡。
- (3)查詢已繫結的物件
import javax.naming.*;
public class TestJNDI
{
public static void main(String[] args)
{
try
{
Context ctx=new InitialContext();
Object object=ctx.lookup(“JNDIName”); //根據JNDI名查詢繫結的物件
String str=(String) object; //強制轉換
}
catch(NamingException e)
{ e.printStackTrace();
}
catch(ClassCastException e)
{ e.printStackTrace();
}
}
}
3、資料庫連線池技術
- (1)傳統的Web資料庫程式設計模式
進行SQL操作,取出資料。
斷開資料庫連線。
使用這種模式開發,存在很多問題。
首先,我們要為每一次WEB請求(例如察看某一篇文章的內容)建立一次資料庫連線,對於一次或幾次操作來講,或許你覺察不到系統的開銷,但是,對於WEB程式來講,即使在某一較短的時間段內,其操作請求數也遠遠不是一兩次,而是數十上百次(想想全世界的網友都有可能在您的網頁上查詢資料),在這種情況下,系統開銷是相當大的。事實上,在一個基於資料庫的WEB系統中,建立資料庫連線的操作將是系統中代價最大的操作之一。很多時候,可能您的網站速度瓶頸就在於此。
其次,使用傳統的模式,你必須去管理每一個連線,確保他們能被正確關閉,如果出現程式異常而導致某些連線未能關閉,將導致資料庫系統中的記憶體洩露,最終我們將不得不重啟資料庫。
頻繁的建立、關閉連線,會極大的減低系統的效能,因為對於連線的使用成了系統性能的瓶頸。
- (2)資料庫連線是一種關鍵的有限的昂貴的資源
連線池是這麼一種機制,當應用程式關閉一個Connection的時候,這個連線被回收,而不是被destroy,因為建立一個連線是一個很費資源的操作。如果能把回收的連線重新利用,會減少新建立連線的數目,顯著的提高執行的效能。該策略的核心思想是:連線複用。
通過採用連線池的方法,伺服器在啟動時先開啟一定數量的連線。 當應用需要連線時,就可以從伺服器請求一個連線。當應用結束該連線時,伺服器就把它釋放到連線池,以備其他客戶機使用。
伺服器監聽客戶的連線請求 客戶獲得連線
- (3)連線池的主要作用
資料庫連線池負責分配、管理和釋放資料庫連線,它允許應用程式重複使用一個現有的資料庫連線,而再不是重新建立一個;
釋放空閒時間超過最大空閒時間的資料庫連線來避免因為沒有釋放資料庫連線而引起的資料庫連線遺漏。這項技術能明顯提高對資料庫操作的效能。
封裝使用者資訊 使用連線池可以封裝連線資料庫系統所用的使用者資訊(帳號和密碼),這樣客戶端程式在建立連線時不用考慮安全資訊。
- (4)資料庫連線池的工作原理
- (5)資料庫連線池的最小連線數和最大連線數
最小連線數是連線池一直保持的資料庫連線,所以如果應用程式對資料庫連線的使用量不大,將會有大量的資料庫連線資源被浪費;
最大連線數是連線池能申請的最大連線數,如果資料庫連線請求超過此數,後面的資料庫連線請求將被加入到等待佇列中,這會影響之後的資料庫操作。
如果最小連線數與最大連線數相差太大,那麼最先的連線請求將會獲利,之後超過最小連線數量的連線請求等價於建立一個新的資料庫連線。不過,這些大於最小連線數的資料庫連線在使用完不會馬上被釋放,它將被放到連線池中等待重複使用或是空閒超時後被釋放。
- (6)使用連線池得到連線
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("jdbc/EmployeeDB");
Connection con = ds.getConnection("myPassword", "myUserName");
或者:
Context ctx = new InitialContext();
ConnectionPoolDataSource ds = (ConnectionPoolDataSource)ctx.lookup("jdbc/EmployeeDB");
PooledConnection con = ds.getConnection("myPassword", "myUserName");
是否使用連線池獲得一個連線,在應用程式的程式碼上是看不出不同的。在使用這個Connection連線上也沒有什麼不一樣的地方,唯一的不同是在java的finally語句塊中來關閉一個連線。在finally中關閉連線是一個好的程式設計習慣。這樣,即使方法丟擲異常,Connection也會被關閉並回收到連線池中去。程式碼應該如下所示:
try
{…
}
catch()
{…
}
finally
{
if(con!=null)
con.close();
}
4、在Tomcat中配置資料庫的連線池
(1)連線池配置(Database Connection Pool (DBCP) Configurations)
DBCP使用的是Jakarta-Commons Database Connection Pool 要使用連線池需要如下的元件即jar檔案。
Jakarta-Commons DBCP 1.1 對應commons-dbcp-1.1.jar。
Jakarta-Commons Collections 2.0 對應commons-collections.jar。
Jakarta-Commons Pool 1.1 對應commons-pool-1.1.jar。這三個jar檔案要與你的JDBC驅動程式一起放到【TOMCAT_HOME】\common\lib目錄下以便讓tomcat和你的web應用都能夠找到。
注:
這三個jar檔案是預設存在與【TOMCAT_HOME】\common\lib下的。
需要注意的地方:第三方的驅動程式或者其他類只能以*.jar的形式放到Tomcat的common\lib目錄中,因為Tomcat只把*.jar檔案加到CLASSPATH中。
不要把上訴三個檔案放到WEB-INF/lib或者其他地方因為這樣會引起混淆。
(2)通過配置阻止連線池漏洞
資料庫連線池建立和管理連線池中建立好的資料庫連線,迴圈使用這些連線以得到更好的效率。這樣比始終為一個使用者保持一個連線和為使用者的請求頻繁的建立和銷燬資料庫連線要高效的多。
這樣就有一個問題出現了,一個Web應用程式必須顯示的釋放ResultSet,Statement和Connection。如果在關閉這些資源的過程中失敗將導致這些資源永遠不在可用,這就是所謂的連線池漏洞。這個漏洞最終會導致連線池中所有的連線不可用。
通過配置Jakarta Common DBCP可以跟蹤和恢復那些被遺棄的資料庫連線。
以下是一系列相關配置:
通過配置DBCP資料來源中的引數removeAbandoned來保證刪除被遺棄的連線使其可以被重新利用。
為ResourceParams(見下文的資料來源配置)標籤新增引數removeAbandoned
<parameter>
<name>removeAbandoned</name>
<value>true</value>
</parameter>
通過這樣配置的以後當連線池中的有效連線接近用完時DBCP將試圖恢復和重用被遺棄的連線。這個引數的值預設是false。
通過設定removeAbandonedTimeout來設定被遺棄的連線的超時的時間,即當一個連線連線被遺棄的時間超過設定的時間時那麼它會自動轉換成可利用的連線。
<parameter>
<name>removeAbandonedTimeout</name>
<value>60</value>
</parameter>
預設的超時時間是300秒。
設定logAbandoned引數,以將被遺棄的資料庫連線的回收記入日誌中
<parameter>
<name>logAbandoned</name>
<value>true</value>
</parameter>
這個引數預設為false。
(3)修改server.xml檔案
<Context path="/WebMis" docBase="WebMis" debug="0" reloadable="true">
<Resource name="jdbc/webmis" auth="Container" type="javax.sql.DataSource"/>
<ResourceParams name="jdbc/webmis">
<parameter>
<name>
factory
</name>
<value>org.apache.commons.dbcp.BasicDataSourceFactory
</value>
</parameter>
<parameter>
<name>
driverClassName
</name>
<value>com.microsoft.jdbc.sqlserver.SQLServerDriver
</value>
</parameter>
<parameter>
<name>
url
</name>
<value>jdbc:microsoft:sqlserver://127.0.0.1:1433;DatabaseName=DataBase
</value>
</parameter>
<parameter>
<name>
username
</name>
<value>
sa
</value>
</parameter>
<parameter>
<name>
password
</name>
<value>
</value>
</parameter>
<parameter>
<name>
maxActive
</name>
<value>
20
</value>
</parameter>
<parameter>
<name>
maxIdle
</name>
<value>10</value>
</parameter>
<parameter>
<name>maxWait</name>
<value>-1</value>
</parameter>
<parameter>
<name>removeAbandoned</name>
<!-- Abandoned DB connections are removed and recycled -->
<value>true</value>
</parameter>
<parameter>
<name>removeAbandonedTimeout</name>
<!-- Use the removeAbandonedTimeout parameter to set the number of seconds a DB connection has been idle before it is considered abandoned. -->
<value>60</value>
</parameter>
<parameter>
<name>logAbandoned</name>
<!-- Log a stack trace of the code which abandoned -->
<value>false</value>
</parameter>
</ResourceParams>
</Context>
注意:
所有的入口和資源都放在JNDI名稱空間裡的java:comp/env段裡
設定JNDI資源要在$CATALINA_HOME/conf/server.xml檔案裡使用下列標誌符:
1) <Resource>--設定應用程式可用的資源的名字和型別(同上面說的<resource-ref>等價)。
2) <ResourceParams>--設定Java資源類工廠的名稱或將用的JavaBean屬性。
上述這些標誌符必須放在<Context>和</Context>之間
(2)、拷貝SQLServer的JDBC驅動程式到Tomcat的\common\lib目錄下
(3)、在程式中利用資料來源來訪問資料庫
try
{
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
DataSource ds = (DataSource)envCtx.lookup("jdbc/webmis");
Connection con=ds.getConnection();
}
catch (NamingException e)
{
e.printStackTrace();
}
catch (SQLException e)
{
e.printStackTrace();
}
5、在server.xml檔案中與資料來源的描述相關的標籤含義
maxActive 連線池的最大資料庫連線數。設為0表示無限制。
maxIdle 資料庫連線的最大空閒時間。超過此空閒時間,資料庫連線將被標記為不可用,然後被釋放。設為0表示無限制。
maxWait 最大建立連線等待時間。如果超過此時間將接到異常。設為-1表示無限制。
removeAbandoned 回收被遺棄的(一般是忘了釋放的)資料庫連線到連線池中。
removeAbandonedTimeout 資料庫連線過多長時間不用將被視為被遺棄而收回連線池中。
logAbandoned 將被遺棄的資料庫連線的回收記入日誌。
driverClassName JDBC驅動程式。
url 資料庫DSN連線字串
6、在Web應用的web.xml檔案中引用該資源
將下面的標籤放在放在<web-app>和</web-app>中間
<!-- Database Config start -->
<resource-ref>
<description>connectDB test</description>
<res-ref-name>jdbc/webmis</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<!-- Database Config end -->
以下是一個綜合配置例項
首先在C:根目錄下建立資料夾mywebapp,作為一個虛擬目錄的位置。
建立一個Sql Server資料庫DataBonus
找到C:\jakarta-tomcat-5.0.19\conf\server.xml,開啟。
<Context path="/mywebapp" docBase="C:/mywebapp" debug="0" reloadable="true">
<Resource name="jdbc/mybonusds" auth="Container" type="javax.sql.DataSource"/>
<ResourceParams name="jdbc/mybonusds">
<parameter>
<name>factory</name>
<value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
</parameter>
<parameter>
<name>driverClassName</name>
<value>com.microsoft.jdbc.sqlserver.SQLServerDriver</value>
</parameter>
<parameter>
<name>url</name>
<value>
jdbc:microsoft:sqlserver://127.0.0.1:1433;DatabaseName=DataBonus
</value>
</parameter>
<parameter>
<name>username</name>
<value>sa</value>
</parameter>
<parameter>
<name>password</name>
<value></value>
</parameter>
<parameter>
<name>maxActive</name>
<value>20</value>
</parameter>
<parameter>
<name>maxIdle</name>
<value>10</value>
</parameter>
<parameter>
<name>maxWait</name>
<value>-1</value>
</parameter>
<parameter>
<name>removeAbandoned</name>
<!-- Abandoned DB connections are removed and recycled -->
<value>true</value>
</parameter>
<parameter>
<name>removeAbandonedTimeout</name>
<!-- Use the removeAbandonedTimeout parameter to set the number of seconds a DB connection has been idle before it is considered abandoned. -->
<value>60</value>
</parameter>
<parameter>
<name>logAbandoned</name>
<!-- Log a stack trace of the code which abandoned -->
<value>false</value>
</parameter>
</ResourceParams>
</Context>
做一個JSP頁面index.jsp放到mywebapp下面,程式碼:
<%--字符集設為"gb2312",使動態頁面支援中文--%>
<%@ page contentType="text/html; charset=GB2312"%>
<!-- 這裡使用一個字串變數 ("PAGETITLE") 保持題目和主標題的一致性。-->
<html>
<head>
<title>
<%= pagetitle %>
</title>
</head>
<body bgcolor=#FFFFFF>
<font face="Helvetica">
<h2>
<font color=#DB1260>
<%= pagetitle %>
</font>
</h2>
<!-- 匯入必要的類和類庫 -->
<%@ page import="
javax.naming.*,
java.sql.*,
javax.sql.DataSource
"%>
<!-- 宣告一個類方法 -->
<%!
//宣告變數
//標題
String pagetitle = "這是JSP呼叫資料庫的例子";
%>
<!-- 下面這些程式碼將被插入到servlet中 -->
<%
java.sql.Connection conn= null;
java.sql.Statement stmt =null;
java.sql.ResultSet rs=null;
try {
// 通過JNDI獲取主介面
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
DataSource ds = (DataSource)envCtx.lookup("jdbc/mybonusds");
conn=ds.getConnection();
stmt = conn.createStatement();
//執行SQL語句
stmt.execute("select * from 獎金");
//取得結果集
rs = stmt.getResultSet();
%>
<table border="1">
<tr>
<td width="60" height="20"><% out.print("編號"); %></td>
<td width="80" height="20"><% out.print("姓名"); %></td>
<td width="200" height="20"><% out.print("發獎名稱"); %></td>
<td width="100" height="20"><% out.print("金額"); %></td>
<td width="200" height="20"><% out.print("備註"); %></td>
</tr>
<% while (rs.next()) {
%>
<tr>
<td width="60" height="20"><% out.print(rs.getString("編號")); %></td>
<td width="80" height="20"><% out.print(rs.getString("姓名")); %></td>
<td width="200" height="20"><% out.print(rs.getString("發獎名稱")); %></td>
<td width="100" height="20"><% out.print(rs.getString("金額")); %></td>
<td width="200" height="20"><% out.print(rs.getString("備註")); %></td>
</tr>
<% } %>
</table>
<%
// Catch exceptions
}
catch (Exception e) {
}
finally {
if (rs != null)
{
try{rs.close();}catch(Exception ignore){};
}
if (stmt != null)
{
try{stmt.close();}catch(Exception ignore){};
}
if (conn != null)
{
try{conn.close();}catch(Exception ignore){};
}
%>
<%
}
%>
</font>
</body>
</html>
啟動Tomcat。
瀏覽:http://127.0.0.1:8080/mywebapp/index.jsp