為什么使用數(shù)據(jù)源
在帳套配置項(xiàng)中,我們使用數(shù)據(jù)源來表示對(duì)應(yīng)的數(shù)據(jù)庫(kù)連接。使用數(shù)據(jù)源有兩個(gè)好處:對(duì)開發(fā)人員屏蔽數(shù)據(jù)庫(kù)細(xì)節(jié),只要通過JNDI取得數(shù)據(jù)源就可以了,無需關(guān)心數(shù)據(jù)庫(kù)連接是如何建立的;數(shù)據(jù)源通常都提供了數(shù)據(jù)庫(kù)連接池的功能。
數(shù)據(jù)庫(kù)連接是一種關(guān)鍵的有限的昂貴的資源,而且數(shù)據(jù)庫(kù)連接的建立和關(guān)閉也是很耗費(fèi)系統(tǒng)資源的。在傳統(tǒng)的兩層C/S架構(gòu)中,一個(gè)客戶端對(duì)應(yīng)一個(gè)數(shù)據(jù)庫(kù)連接,在用戶活動(dòng)期間就獨(dú)占此連接;而在分布式系統(tǒng)中,數(shù)據(jù)庫(kù)連接的建立與關(guān)閉是異常頻繁的,因此數(shù)據(jù)庫(kù)連接的對(duì)系統(tǒng)的性能影響更是明顯。對(duì)數(shù)據(jù)庫(kù)連接的管理能顯著影響到整個(gè)應(yīng)用程序的伸縮性和健壯性,影響到程序的性能指標(biāo)。數(shù)據(jù)庫(kù)連接池正是針對(duì)這個(gè)問題提出來的。
數(shù)據(jù)庫(kù)連接池在初始化時(shí)將創(chuàng)建一定數(shù)量的數(shù)據(jù)庫(kù)連接放到連接池中,這些數(shù)據(jù)庫(kù)連接的數(shù)量是由最小數(shù)據(jù)庫(kù)連接數(shù)來設(shè)定的。數(shù)據(jù)庫(kù)連接池負(fù)責(zé)分配、管理和釋放數(shù)據(jù)庫(kù)連接,它允許應(yīng)用程序重復(fù)使用一個(gè)現(xiàn)有的數(shù)據(jù)庫(kù)連接,而再不是重新建立一個(gè);釋放空閑時(shí)間超過最大空閑時(shí)間的數(shù)據(jù)庫(kù)連接來避免因?yàn)闆]有釋放數(shù)據(jù)庫(kù)連接而引起的數(shù)據(jù)庫(kù)連接遺漏。無論這些數(shù)據(jù)庫(kù)連接是否被使用,連接池都將一直保證至少擁有這么多的連接數(shù)量。連接池的最大數(shù)據(jù)庫(kù)連接數(shù)量限定了這個(gè)連接池能占有的最大連接數(shù),當(dāng)應(yīng)用程序向連接池請(qǐng)求的連接數(shù)超過最大連接數(shù)量時(shí),這些請(qǐng)求將被加入到等待隊(duì)列中。
JDBC3.0規(guī)范中規(guī)定了如下的接口和類來實(shí)現(xiàn)數(shù)據(jù)庫(kù)連接池:
javax.sql.ConnectionEvent:連接事件
javax.sql.ConnectionPoolDataSource:連接池?cái)?shù)據(jù)源
javax.sql.PooledConnection:被池化的連接
javax.sql.ConnectionEventListener:連接事件監(jiān)聽接口
上邊這些接口和類是對(duì)數(shù)據(jù)庫(kù)連接池內(nèi)部實(shí)現(xiàn)的規(guī)定,對(duì)于使用者來說是透明的。數(shù)據(jù)庫(kù)連接池的使用者一般只和DataSource接口直接打交道,通過這個(gè)接口獲得數(shù)據(jù)庫(kù)連接,其主要方法為:
Connection getConnection():得到一個(gè)數(shù)據(jù)庫(kù)連接
Connection getConnection(String userName,String password):得到一個(gè)數(shù)據(jù)庫(kù)連接
java.io.PrintWriter getLogWriter():獲得Log Writer的對(duì)象
void setLogWriter(java.io.PrintWriter out):設(shè)置Log Writer
void setLoginTimeout(int seconds):設(shè)置數(shù)據(jù)源嘗試連接數(shù)據(jù)庫(kù)的最大時(shí)間
int getLoginTimeout():獲得數(shù)據(jù)源嘗試連接數(shù)據(jù)庫(kù)的最大時(shí)間
開源社區(qū)中有很多數(shù)據(jù)庫(kù)連接池的實(shí)現(xiàn),比如PoolMan等,使用這些數(shù)據(jù)庫(kù)連接池包可以保證跨應(yīng)用服務(wù)器的移植。不過在本案例系統(tǒng)中,我們使用應(yīng)用服務(wù)器的數(shù)據(jù)源功能提供的數(shù)據(jù)庫(kù)連接池。數(shù)據(jù)源在不同的服務(wù)器中有不同的配置方式,下面介紹Tomcat中數(shù)據(jù)源的配置。
打開%TOMCAT_HOME%\conf\server.xml,在</Context>和</host>前添加如下配置文件項(xiàng):
<Context docBase="CowNewPIS" path="/CowNewPIS"??????reloadable="true">
<Resource type="javax.sql.DataSource"
??????auth="Container" name="jdbc/PISMSSQL_Dev" />
<ResourceParams name="jdbc/PISMSSQL_Dev">
<parameter>
<name>maxWait</name>
<value>5000</value>
</parameter>
<parameter>
<name>maxActive</name>
<value>4</value>
</parameter>
<parameter>
<name>password</name>
<value></value>
</parameter>
<parameter>
<name>url</name>
<value>
jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=PISDev1106
</value>
</parameter>
<parameter>
<name>driverClassName</name>
<value>
com.microsoft.jdbc.sqlserver.SQLServerDriver
????</value>
</parameter>
<parameter>
<name>maxIdle</name>
<value>2</value>
</parameter>
<parameter>
<name>username</name>
<value>sa</value>
</parameter>
</ResourceParams>
</Context>
?
在配置的時(shí)候,要指定數(shù)據(jù)庫(kù)的JDBC驅(qū)動(dòng)、數(shù)據(jù)庫(kù)連接URL等。數(shù)據(jù)源配置完畢,重啟服務(wù)器。編寫一個(gè)測(cè)試客戶端:
Context ctx=null;
Connection conn=null;
try
{
ctx=new InitialContext();
DataSource ds=(DataSource)ctx.lookup("java:comp/env/jdbc/PISMSSQL_Dev");
conn=ds.getConnection();
}
finally
{
if(conn!=null)
conn.close();
if(ctx!=null)
ctx.close();
}
Tomcat啟動(dòng)的時(shí)候會(huì)將Server.xml中的數(shù)據(jù)源配置綁定到JNDI中,我們可以在應(yīng)用服務(wù)器啟動(dòng)的時(shí)候用代碼來代替Tomcat完成綁定:
BasicDataSource bdds = new BasicDataSource();
//設(shè)置數(shù)據(jù)庫(kù)驅(qū)動(dòng)
bdds.setDriverClassName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
//設(shè)置JDBC的URL
bdds.setUrl("jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=PISDev1106");
bdds.setUsername("sa");
//設(shè)置連接池初始大小
bdds.setInitialSize(2);?????
//JNDI配置
Map env = new Hashtable();
env.put("java.naming.factory.initial",
"org.apache.naming.java.javaURLContextFactory");
InitialContext ctx=new InitialContext(env);?????
//數(shù)據(jù)源綁定到JNDI
ctx.bind("jdbc/PISMSSQL_Dev",bdds);
這樣我們可以把數(shù)據(jù)源的配置文件移到ServerConfig.xml中,增加類似如下的配置:
<DataSources>
<DataSource
name=”jdbc/PISMSSQL_Dev” driverClassName=”com.microsoft.jdbc.sqlserver.SQLServerDriver”
url=”jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=PISDev1106”
userName=”sa”
>
</DataSource>
</DataSources>
在應(yīng)用服務(wù)器啟動(dòng)的時(shí)候,到ServerConfig.xml中讀取數(shù)據(jù)源配置完成綁定。這種方式一是減少了實(shí)施人員配置文件的工作量,服務(wù)端的任何配置都可以在這個(gè)配置文件中完成;二是使得系統(tǒng)在不同服務(wù)器之間移植變得更加容易。