Java Naming and Directory Interface (JNDI)JNDI API被用于執行名字和目錄服務(wù)。它提供了一致的模型來(lái)存取和操作企業(yè)級的資源如DNS和LDAP,本地文件系統,后者在應用服務(wù)器中的對象。在JNDI中,在目錄結構中的每一個(gè)結點(diǎn)稱(chēng)為context。每一個(gè)JNDI名字都是相對于context的。應用可以通過(guò)這個(gè)初始化的context經(jīng)有這個(gè)目錄樹(shù)來(lái)定位它所需要的資源或對象。
JNDI相對與JDBC來(lái)說(shuō)是他的靈活性,程序員不需要關(guān)心“具體的數據庫后臺是什么?JDBC驅動(dòng)程序是什么?JDBCURL格式是什么?訪(fǎng)問(wèn)數據庫的用戶(hù)名和口令是什么?”等等這些問(wèn)題,程序員編寫(xiě)的程序應該沒(méi)有對 JDBC 驅動(dòng)程序的引用,沒(méi)有服務(wù)器名稱(chēng),沒(méi)有用戶(hù)名稱(chēng)或口令 —— 甚至沒(méi)有數據庫池或連接管理。而是把這些問(wèn)題交給J2EE容器來(lái)配置和管理,程序員只需要對這些配置和管理進(jìn)行引用即可。
理解連接池
連接池是創(chuàng )建和管理多個(gè)連接的一種技術(shù),這些連接可被需要使用它們的任何線(xiàn)程使用。連接池技術(shù)基于下述事實(shí):對于大多數應用程序,當它們正在處理通常需要數毫秒完成的事務(wù)時(shí),僅需要能夠訪(fǎng)問(wèn)JDBC連接的1個(gè)線(xiàn)程。未處理事務(wù)時(shí),連接處于閑置狀態(tài)。使用連接池,允許其他線(xiàn)程使用閑置連接來(lái)執行有用的任務(wù)。
事實(shí)上,當某一線(xiàn)程需要用JDBC在MySQL或其他數據庫上執行操作時(shí),需要用到由連接池提供的連接。使用連接完成線(xiàn)程后,線(xiàn)程會(huì )將連接返回給連接池,以便該連接能夠被其他需要使用連接的線(xiàn)程使用。
從連接池“借出”連接時(shí),該連接僅供請求它的線(xiàn)程使用。從編程觀(guān)點(diǎn)看,其效果等同于每次需要JDBC連接時(shí)調用DriverManager.getConnection(),但是,采用連接池技術(shù),可通過(guò)使用新的或已有的連接結束線(xiàn)程。
連接池技術(shù)能顯著(zhù)增加Java應用程序的性能,同時(shí)還能降低資源使用率。連接池技術(shù)的主要優(yōu)點(diǎn)包括:
· 縮短了連接創(chuàng )建時(shí)間
與其他數據庫相比,MySQL提供了快速的連接設置功能,連接時(shí)間通常不是問(wèn)題,但創(chuàng )建新的JDBC連接仍會(huì )導致聯(lián)網(wǎng)操作和一定的IDBC驅動(dòng)開(kāi)銷(xiāo),如果這類(lèi)連接是“循環(huán)”使用的,使用該方式,可避免這類(lèi)不利因素。
·簡(jiǎn)化的編程模型
使用連接池技術(shù)時(shí),每個(gè)單獨線(xiàn)程能夠像創(chuàng )建了自己的JDBC連接那樣進(jìn)行操作,從而允許使用直接的JDBC編程技術(shù)。
·受控的資源使用
如果不使用連接池技術(shù),而是在每次需要時(shí)為線(xiàn)程創(chuàng )建新的連接,那么應用程序的資源使用將十分浪費,而且在負載較重的情況下會(huì )導致無(wú)法預期的結果。
注意,與MySQL的每個(gè)連接均會(huì )在客戶(hù)端和服務(wù)器端造成一定的開(kāi)銷(xiāo)(每寸、CPU、關(guān)聯(lián)轉換等)。每個(gè)連接均會(huì )對應用程序和MySQL服務(wù)器的可用資源帶來(lái)一定的限制。無(wú)論連接是否執行任何有用的任務(wù),仍將使用這些資源中的相當一部分。
連接池能夠使性能最大化,同時(shí)還能將資源利用控制在一定的水平之下,如果超過(guò)該水平,應用程序將崩潰而不僅僅是變慢。
幸運的是,Sun公司通過(guò)JDBC-2.0“可選”接口,完成了JDBC中連接池概念的標準化實(shí)施,所有主要應用服務(wù)器均實(shí)施了能夠與MySQL Connector/J一起良好工作的這類(lèi)API。
通常,你可以在應用服務(wù)器的配置文件中配置連接池,并通過(guò)Java命名和目錄接口(JNDI)訪(fǎng)問(wèn)它。在下面的代碼中,介紹了在J2E應用服務(wù)器上運行的應用程序中使用連接池的方法:
示例26.12. 與J2EE應用服務(wù)器一起使用連接池
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import javax.naming.InitialContext;
import javax.sql.DataSource;
public class MyServletJspOrEjb {
public void doSomething() throws Exception {
/*
* Create a JNDI Initial context to be able to
* lookup the DataSource
*
* In production-level code, this should be cached as
* an instance or static variable, as it can
* be quite expensive to create a JNDI context.
*
* Note: This code only works when you are using servlets
* or EJBs in a J2EE application server. If you are
* using connection pooling in standalone Java code, you
* will have to create/configure datasources using whatever
* mechanisms your particular connection pooling library
* provides.
*/
InitialContext ctx = new InitialContext();
/*
* Lookup the DataSource, which will be backed by a pool
* that the application server provides. DataSourceinstances
* are also a good candidate for caching as an instance
* variable, as JNDI lookups can be expensive as well.
*/
DataSource ds =(DataSource)ctx.lookup("java:comp/env/jdbc/MySQLDB");
/*
* The following code is what would actually be in your
* Servlet, JSP or EJB 'service' method...where you need
* to work with a JDBC connection.
*/
Connection conn = null;
Statement stmt = null;
try {
conn = ds.getConnection();
/*
* Now, use normal JDBC programming to work with
* MySQL, making sure to close each resource when you're
* finished with it, which allows the connection pool
* resources to be recovered as quickly as possible
*/
stmt = conn.createStatement();
stmt.execute("SOME SQL QUERY");
stmt.close();
stmt = null;
conn.close();
conn = null;
} finally {
/*
* close any jdbc instances here that weren't
* explicitly closed during normal code path, so
* that we don't 'leak' resources...
*/
if (stmt != null) {
try {
stmt.close();
} catch (sqlexception sqlex) {
// ignore -- as we can't do anything about ithere
}
stmt = null;
}
if (conn != null) {
try {
conn.close();
} catch (sqlexception sqlex) {
// ignore -- as we can't do anything about ithere
}
conn = null;
}
}
}
}
如上例所示,獲得JNDI InitialContext并查找到數據庫后,其余代碼與過(guò)去在JDBC編程中使用的類(lèi)似。
使用連接池時(shí)需要牢記的最重要事項是,無(wú)論在代碼中出現了什么(異常、控制流等),連接以及由連接創(chuàng )建的任何部分(語(yǔ)句、結果集等)均應被關(guān)閉,以便能再次使用它們。如不然,它們將糾纏在一起,在最好的情況下,意味著(zhù)它們所代表的MySQL服務(wù)器資源(緩沖區、鎖定、套接字等)可能會(huì )捆綁一段時(shí)間,在最壞的情況下,可能會(huì )導致永久捆綁。
連接池的最佳大小是什么?
與所有其他配置經(jīng)驗規則一樣,回答是“它取決于具體情況”。盡管最佳大小取決與預期的負載和平均的數據庫事務(wù)時(shí)間,最佳的連接池大小小于你的預期。例如,如果使用的是Sun公司的Java Petstore Blueprint應用程序,對于包含15~20個(gè)連接的連接池,使用MySQL和Tomcat,在可接受的相應時(shí)間下,可服務(wù)于中等程度的負載(600個(gè)并發(fā)用戶(hù))。
要想確定用于應用程序的連接池大小,應使用諸如ApacheJmeter或The Grinder等工具創(chuàng )建負載測試腳本,并對應用程序進(jìn)行負載測試。
確定出發(fā)點(diǎn)的一種簡(jiǎn)單方法是,將連接池的最大連接數配置為“無(wú)限”,運行負載測試,并測量最大的并發(fā)連接數。隨后,應進(jìn)行反向操作,確定出使應用程序具有最佳性能的連接池的最小和最大值。
聯(lián)系客服