作者:baggio785
日期:2006-4-24
關(guān)鍵詞:DataSource(數(shù)據(jù)源),Tomcat
,連接池
前言
本文根據(jù)實例詳細介紹了如何在tomcat中配置數(shù)據(jù)源。網(wǎng)上此類文章很多,但是基本都是雷同的,而且對一些特殊問題以及原理并未詳細闡述,所以想根據(jù)自己的實際經(jīng)驗,并結(jié)合例子寫一篇詳細的文章。
本文是偶的一些拙見,有不正確的地方請大家多多評論指正
。
開發(fā)環(huán)境
本文的環(huán)境:JDK1.4.2,TOMCAT5.0.28,Oracle9i
JDBC簡介
提到數(shù)據(jù)源,那就不能不說JDBC。JDBC是Java Database Connectivity的縮寫。在java.sql包中提供了JDBC API,定義了訪問數(shù)據(jù)庫的接口和類。但是JDBC API不能直接訪問數(shù)據(jù)庫,必須依賴于數(shù)據(jù)庫廠商提供的JDBC驅(qū)動程序,即JDBC DRIVER。
Java.sql
中常用的接口和類如下:
?????? Driver
接口和
DriverManager
類
?????? Connection
?????? Statement
?????? PreparedSataement
?????? ResultSet
?
1???? Driver
接口和
DriverManager
類
?????? DriverManager
類用來建立和數(shù)據(jù)庫的連接以及管理
JDBC
驅(qū)動程序,常用方法如下:
方法
|
描述
|
registerDriver(Driver driver)
|
在
DriverManager
中注冊
JDBC
驅(qū)動程序
|
getConnection(String url,String user,String pwd)
|
建立和數(shù)據(jù)庫的連接,返回
Connection
對象
|
setLoginTimeOut(int seconds)
|
設(shè)定等待數(shù)據(jù)庫連接的最長時間
|
setLogWriter(PrintWriter out)
|
設(shè)定輸入數(shù)據(jù)庫日至的
PrintWriter
對象
|
2???? Connection
?????? Connection
代表和數(shù)據(jù)庫的連接,其常用方法如下:
方法
|
描述
|
getMetaData()
|
返回數(shù)據(jù)庫的
MetaData
數(shù)據(jù)。
MetaData
數(shù)據(jù)包含了數(shù)據(jù)庫的相關(guān)信息,例如當前數(shù)據(jù)庫連接的用戶名、使用的
JDBC
驅(qū)動程序、數(shù)據(jù)庫允許的最大連接數(shù)、數(shù)據(jù)庫的版本等等。
|
createStatement()
|
創(chuàng)建并返回
Statement
對象
|
PrepareStatement(String sql)
|
創(chuàng)建并返回
prepareStatement
對象
|
3
???? Statement
?????? Statement
用來執(zhí)行靜態(tài)
sql
語句。例如,對于
insert
、
update
、
delete
語句,調(diào)用
executeUpdate(String sql)
方法,而
select
語句可以調(diào)用
executeQuery(String sql)
方法,
executeQuery(String sql)
方法返回
ResultSet
對象。
4
????
PrepareStatement
?? PrepareStatement
用于執(zhí)行動態(tài)的
sql
語句,即允許
sql
語句中包含參數(shù)。使用方法為:
?? String sql = “select col1 from tablename where col2=? And col3=?”;
?? PrepareStatement perpStmt = conn.preparestatement(sql);
?? perpStmt.setstring(1,col2Value);
????? perpStmt.setFloat(2,col3Value);
????? ResultSet rs = perpStmt.executeQuery();
5
????
ResultSet
ResultSet
用來表示
select
語句查詢得到的記錄集,一個
StateMent
對象在同一時刻只能打開一個
ResultSet
對象。通過
ResultSet
的
getXXX()
方法來得到字段值。
ResultSet
提供了
getString()
、
getFloat()
、
getInt()
等方法。可以通過字段的序號或者字段的名字來制定獲取某個字段的值。例如:在上例中
getString(0),getString(col1)
都可以獲得字段
col1
的值。
事務(wù)處理
在實際應用中,我們會遇到同時提交多個
sql
語句,這些
sql
語句要么全部成功,要么全部失敗,如果其中一條提交失敗,則必須撤銷整個事務(wù)。為此,
Connection
類提供了
3
個控制事務(wù)的方法:
方法
|
描述
|
setAutoCommit(boolen autoCommit)
|
設(shè)置是否自動提交事務(wù),默認為自動提交
。
|
commit()
|
提交事務(wù)
|
rollback()
|
撤銷事務(wù)
|
參考例子:
try{
conn.SetautoCommit(false);
stmt = conn.createstatement(); stmt.executeUpdate(“delete form table1 where col1=1”); stmt.eecuteUpdate(“delete from table2 where col2=1”);
conn.comm.it();
}catch(Exception e){
?????? e.printStackTrace;
try{
?????? ?????? conn.rollback();
} catch(Exception e1){
?????? e1.printStackTrace;
}
}
|
通過一個
JSP
例子來訪問
oracle
數(shù)據(jù)庫:
<%@ page import=”java.util.*”>
<%@ page import=”java.sql.*”>
<%
try{
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
//
加載
oracle
驅(qū)動程序
Class.forName(“oracle.jdbc.driver.OracleDriver.”);
//
注冊
oracle
驅(qū)動程序
DriverManager.regidterDriver(new oracle.jdbc.driver.OracleDriver());
//
建立數(shù)據(jù)庫連接
conn=DriverManager.getConnection(“jdbc:oracle:thin:@your db ip:your db port:sid”,dbuser,dbpassword);
stmt = conn.createStatement();
rs = stmt.executeQuery(“select * from tablename”);
while(rs.next){
?????? out.print(rs.getstring(“colname”));
}
}catch(Exception e){
}
finally{
rs.close();
stmt.close();
conn.close();
}
%>
|
數(shù)據(jù)源簡介
JDBC2.0
提供了
javax.sql.DataSource
的接口,負責與數(shù)據(jù)庫建立連接,實際應用時不需要編寫連接數(shù)據(jù)庫代碼,直接從數(shù)據(jù)源獲得數(shù)據(jù)庫的連接。
Dataource
中事先建立了多個數(shù)據(jù)庫連接,這些數(shù)據(jù)庫連接保持在數(shù)據(jù)庫連接池中,當程序訪問數(shù)據(jù)庫時,只需要從連接池從取出空閑的連接,訪問數(shù)據(jù)庫結(jié)束,在將這些連接歸還給連接池。
DataSource
對象由容器(
Tomcat
)提供,不能使用創(chuàng)建實例的方法來生成
DataSource
對象,要采用
JAVA
的
JNDI
(
Java Nameing and Directory Interface
,
java
命名和目錄接口)來獲得
DataSource
對象的引用。(另有一種說法:“其實從技術(shù)上來說,數(shù)據(jù)源連接方式是不需要目錄服務(wù)的,我們同樣可以通過序列化數(shù)據(jù)源對象直接訪問文件系統(tǒng)。這點是需要明確的。”感興趣的朋友可以試試。)
JNDI
是一種將對象和名字綁定的技術(shù),對象工廠負責生產(chǎn)出對象,這些對象都和唯一的名字相綁定。程序中可以通過這個名字來獲得對象的引用。
Tomcat
把
DataSource
作為一種可配置的
JNDI
資源來處理,生成
DataSource
對象的工廠為
org.apache.comm.ons.dbcp.BasicDataSourceFactory
。
?
配置數(shù)據(jù)源
配置數(shù)據(jù)源其實相當簡單:
首先在
server.xml
中加入
<Resource>
元素,打開
server.xml
,在
<Context>
中加入以下代碼(以
oracle
為例):
<Resource name="jdbc/ JNDI
名字
"
?????????????? auth="Container"
?????????????? type="javax.sql.DataSource"/>
?<ResourceParams name="jdbc/JNDI
名字
">
??? <parameter>
?????<name>factory</name>
????? <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
??? </parameter>
??? <parameter>
????? <name>maxActive</name>
????? <value>100</value>
??? </parameter>
??? <parameter>
????? <name>maxIdle</name>
????? <value>30</value>
??? </parameter>
?
??? <parameter>
????? <name>maxWait</name>
????? <value>10000</value>
??? </parameter>
?
??? <parameter>
???? <name>username</name>
???? <value>
用戶名
</value>
??? </parameter>
??? <parameter>
???? <name>password</name>
???? <value>
密碼
</value>
??? </parameter>
?
??? <parameter>
?????? <name>driverClassName</name>
?????? <value>oracle.jdbc.driver.OracleDriver</value>
??? </parameter>
?
??? <parameter>
?? ???<name>url</name>
????? <value>jdbc:oracle:thin:@ip:
端口
:sid </value>
??? </parameter>
?</ResourceParams>
|
<Resource>
元素的屬性如下:
屬性
|
描述
|
name
|
指定
Resource
的
JNDI
的名字
|
auth
|
指定管理
Resource
的
Manager
,由兩個可選值:
Container
和
Application
。
Container
表示由容器來創(chuàng)建和管理
Resource
,
Application
表示由
WEB
應用來創(chuàng)建和管理
Resource
。如果在
web application deployment descriptor
中使用
<resource-ref>
,這個屬性是必需的,如果使用
<resource-env-ref>
,這個屬性是可選的。
|
type
|
指定
Resource
所屬的
java
類名
|
<ResourceParams>
元素的屬性如下:
屬性
|
描述
|
name
|
指定
ResourceParams
的
JNDI
的名字,必須和
Resource
的
name
保持一致
|
factory
|
指定生成
DataSource
對象的
factory
的類名
|
maxActive
|
指定數(shù)據(jù)庫連接池中處于活動狀態(tài)的數(shù)據(jù)庫連接最大數(shù)目,
0
表示不受限制
|
maxIdle
|
指定數(shù)據(jù)庫連接池中
處于
空閑狀態(tài)的數(shù)據(jù)庫連接的最大數(shù)目,
0
表示不受限制
|
maxWait
|
指定數(shù)據(jù)庫連接池中的數(shù)據(jù)庫連接處于空閑狀態(tài)的最長時間(單位為毫秒),超過這一事件,將會拋出異常。
-1
表示可以無限期等待。
|
username
|
指定連接數(shù)據(jù)庫的用戶名
|
password
|
指定連接數(shù)據(jù)庫的密碼
|
driverClassName
|
指定連接數(shù)據(jù)庫的
JDBC
驅(qū)動程序
|
url
|
指定連接數(shù)據(jù)庫的
URL
|
其他文章說以上配置就OK了,對于web.xml的配置可有可無,其實不是這樣子的。如果在web應用中訪問了由Servlet容器管理的某個JNDI Resource,則必須在web.xml中聲明對這個JNDI Resource的引用。表示資源引用的元素為<resource-ref>,該元素加在<wepapp></ wepapp >中。
<resource-ref>
???? <descryiption>DB Connection</descryiption>
<res-ref-name>jdbc/JNDI
名字
</ res-ref-name>
<res-type>javax.sql.DataSource </ res- type>
<res-auth>Container </ res- auth>
</resource-ref>
|
<resource-ref>
元素的屬性如下:
屬性
|
描述
|
description
|
對所引用的資源的說明
|
res-ref-name
|
指定所引用資源的
JNDI
名字,與
<Resource>
元素中的
name
屬性保持一致
|
res-type
|
指定所引用資源的類名字,與
<Resource>
元素中的
type
屬性保持一致
|
res-auth
|
指定所引用資源的
Manager
,與
<Resource>
元素中的
auth
屬性保持一致
|
到這里,數(shù)據(jù)源就已經(jīng)配置成功了。但是我在測試的時候除了一點小麻煩,主要原因是對DataSource的概念沒搞清楚。我是這么測試的,寫一個測試類,然后在eclipse中進行junit測試,
捕獲的異常為:
javax.naming.NoInitialContextException
: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:?java.naming.factory.initia
l
。
同樣的代碼在JSP文件中正常運行,后來翻了一些資料,終于找到了問題的所在了。原來DataSource是由容器(TOMCAT)提供的,所以我的測試會拋出異常。為了再次驗證想法是否正確,在jsp文件中import剛才拋出異常的類,在進行連接數(shù)據(jù)庫,結(jié)果一切正常。
下面的例子是實際應用中使用
DataSource
,在
jsp
文件中連接
oracle
。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ page import="java.sql.*"%>
<%@ page import="javax.naming.*"%>
<%@ page import="javax.sql.*"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
?<head>
?</head>
<body>
<%
Context initContext = new InitialContext();
Context envContext = (Context) initContext.lookup("java:/comp/env");
DataSource db = (DataSource)envContext.lookup("jdbc/javablogorl");
// javablogorl
為
<Resource>
元素中
name
屬性的值
Connection conn = db.getConnection( );?
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM blog_systemadmin");
while(rs.next()){
?????? out.print(rs.getString("admin_name")+" ");
?????? out.print(rs.getString("admin_password")+"<br>");
}
rs.close();
stmt.close();
conn.close();
%>?
?</body>
</html>
|
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=674822