天天看點

jdbc 和 jndi 的關系

 Java Database Connectivity(JDBC)JDBC以一種統一的方式來對各種各樣的資料庫進行存取。和ODBC一樣,JDBC為開發人員隐藏了不同資料庫的不同特性。另外,由于JDBC建立在Java的基礎上,是以還提供了資料庫存取的平台獨立性。JDBC定義了4種不同的驅動程式:JDBC-ODBCBridge、JDBC-native driverbridge、JDBC-networkbridge、PureJavadriver。在一個多層的企業級應用中,更大的可能是在用戶端和一個EJB進行通信,采用EJB建立資料庫連接配接。為了實作和改進可伸縮性和系統性能, 也可以采用連接配接緩沖池(connection pool)優化資料庫連接配接。

Java Naming and Directory Interface (JNDI)JNDI API被用于執行名字和目錄服務。它提供了一緻的模型來存取和操作企業級的資源如DNS和LDAP,本地檔案系統,後者在應用伺服器中的對象。在JNDI中,在目錄結構中的每一個結點稱為context。每一個JNDI名字都是相對于context的。應用可以通過這個初始化的context經有這個目錄樹來定位它所需要的資源或對象。(這句話什麼意思呢?是這樣的:

JNDI 對應于J2SE中的javax.naming包,這套API的主要作用在于:它可以把Java對象放在一個容器中(JNDI容器),并為容器中的java對象取一個名稱,以後程式想獲得Java對象,隻需通過名稱檢索即可。 

其核心API為Context,它代表JNDI容器,其lookup方法為檢索容器中對應名稱的對象。

JNDI的結構:

JNDI的結構自上而下包含3個主要層次:

1)應用層:該層使用JNDI API

2)JNDI API層:該層定義一組類和接口,可以用來通路任何命名或目錄服務。

   JNDI類庫包含在 java2 SDK中,主要包含如下程式包:

1、用于命名操作的javax.naming;

2、用于目錄操作的javax.naming.directory

3、在命名和目錄伺服器中請求事件通知的javax.naming.event;

4、提供LDAP支援的javax.naming.ldap

3)實作層:該層為JNDI SPI API及其具體實作,它包括以下幾個命名/目錄伺服器提供者:LDAP,CORBA,RMI,DNS等。

JNDI命名與上下文:

  JNDI命名服務對象映射為名稱,這種映射可以獲得遠端對象的引用,以及調用遠端對象的方法,而不必知道該對象在網絡上的實體位址。可以使用javax.naming程式包來通路JNDI命名服務,這個程式包包括如下命名方法: 獲得初始上下文,把對象綁定到名稱上,查找對象等。

 在命名系統中,上下文作為查找對象過程的起點。在檔案系統中,每個目錄都可以看做是一個上下文。JNDI API定義了Context接口,該接口在JNDI中起着重要作用。JNDI還定義了InitialContext類,要執行任何操作,必須建立一個InitialContext。

JNDI相對與JDBC來說是他的靈活性,程式員不需要關心“具體的資料庫背景是什麼?JDBC驅動程式是什麼?JDBC URL格式是什麼?通路資料庫的使用者名和密碼是什麼?”等等這些問題,程式員編寫的程式應該沒有對 JDBC 驅動程式的引用,沒有伺服器名稱,沒有使用者名稱或密碼 —— 甚至沒有資料庫池或連接配接管理。而是把這些問題交給J2EE容器來配置和管理(比如weblogic),程式員隻需要對這些配置和管理進行引用即可。

了解連接配接池

連接配接池技術能顯著增加Java應用程式的性能,同時還能降低資源使用率。連接配接池技術的主要優點包括:

·         縮短了連接配接建立時間

與其他資料庫相比,MySQL提供了快速的連接配接設定功能,連接配接時間通常不是問題,但建立新的JDBC連接配接仍會導緻聯網操作和一定的IDBC驅動開銷,如果這類連接配接是“循環”使用的,使用該方式,可避免這類不利因素。

·         簡化的程式設計模型

使用連接配接池技術時,每個單獨線程能夠像建立了自己的JDBC連接配接那樣進行操作,進而允許使用直接的JDBC程式設計技術。

·         受控的資源使用

如果不使用連接配接池技術,而是在每次需要時為線程建立新的連接配接,那麼應用程式的資源使用将十分浪費,而且在負載較重的情況下會導緻無法預期的結果。連接配接池能夠使性能最大化,同時還能将資源利用控制在一定的水準之下,如果超過該水準,應用程式将崩潰而不僅僅是變慢。

幸運的是,Sun公司通過JDBC-2.0“可選”接口,完成了JDBC中連接配接池概念的标準化實施,所有主要應用伺服器均實施了能夠與MySQL Connector/J一起良好工作的這類API。

通常,你可以在應用伺服器的配置檔案中配置連接配接池,并通過Java命名和目錄接口(JNDI)通路它。在下面的代碼中,介紹了在J2E應用伺服器上運作的應用程式中使用連接配接池的方法:

示例26.12. 與J2EE應用伺服器一起使用連接配接池

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.(建立一個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. DataSource instances

          * 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 it here

                }

                stmt = null;

            }

            if (conn != null) {

                    conn.close();

                    // ignore -- as we can't do anything about it here

                conn = null;

        }

    }

}

如上例所示,獲得JNDI InitialContext并查找到資料庫後,其餘代碼與過去在JDBC程式設計中使用的類似。

使用連接配接池時需要牢記的最重要事項是,無論在代碼中出現了什麼(異常、控制流等),連接配接以及由連接配接建立的任何部分(語句、結果集等)均應被關閉,以便能再次使用它們。如不然,它們将糾纏在一起,在最好的情況下,意味着它們所代表的MySQL伺服器資源(緩沖區、鎖定、套接字等)可能會捆綁一段時間,在最壞的情況下,可能會導緻永久捆綁。

連接配接池的最佳大小是什麼?

與所有其他配置經驗規則一樣,回答是“它取決于具體情況”。盡管最佳大小取決與預期的負載和平均的資料庫事務時間,最佳的連接配接池大小小于你的預期。例如,如果使用的是Sun公司的Java Petstore Blueprint應用程式,對于包含15~20個連接配接的連接配接池,使用MySQL和Tomcat,在可接受的相應時間下,可服務于中等程度的負載(600個并發使用者)。

要想确定用于應用程式的連接配接池大小,應使用諸如Apache Jmeter或The Grinder等工具建立負載測試腳本,并對應用程式進行負載測試。

确定出發點的一種簡單方法是,将連接配接池的最大連接配接數配置為“無限”,運作負載測試,并測量最大的并發連接配接數。随後,應進行反向操作,确定出使應用程式具有最佳性能的連接配接池的最小和最大值。

什麼是命名服務?

命名服務在一個集中位置存儲資訊,這樣使用者、計算機和應用程式便可通過網絡進行通信。命名服務使用名稱查找對象,而不是對象的實體ID。比如說在tomcat中查找JDBC資料源不是通過資料源的直接引用查找,而是通過JNDI與資料源綁定的名稱查找(這句話,驗證了我之前的猜想:JNDI這種命名服務接口,綁定了使用jdbc配置的資料源,正因為有了java命名和目錄服務 即JNDI,是以使用者隻需要知道這個資料源的名稱,就能調用該資料源,完成對資料庫的連接配接操作),比如說通過DNS可以使用域名來通路Web應用,而不是直接通過輸入Web伺服器的IP位址來通路,這裡的資料源的引用和IP位址都可以看作是資源的實體ID。命名服務有DNS,NIS,LDAP等。DNS稱為域名系統,開發 DNS 後,網絡中的計算機可由通用名稱而非 Internet (IP)位址來辨別。NIS稱為網絡資訊服務,NIS 的主要作用是通過對各種網絡資訊進行集中控制來更好地管理網絡。NIS 存儲有關網絡、計算機名稱和位址、使用者、以及網絡服務的資訊。

什麼是目錄服務?

目錄服務是命名服務的擴充,目錄服務的對象不單有名稱,還有屬性,既可以通過名稱查找對象,也可以通過屬性查找到一批對象然後篩選出自己需要的對象。目錄服務應該比命名服務更廣發,它可以将整個網絡中的資源和裝置組織起來,形成一個大的目錄,然後通過目錄就可以定位資源和裝置,實作集中管理。

tomcat或Jboss的資料源屬于什麼服務?

屬于命名服務,因為tomcat和Jbosss容器提供了命名服務或者目錄服務,然後程式設計人員想用使用它們的服務時假如沒有JNDI則必須遵照它們定的規範來開發,顯然兩個容器的使用服務的方法是不一樣的,是以才有JNDI的規範。也就是說命名和目錄服務并不是因為程式設計而存在的,而是Web容器本身就具有的。