JNDI与JDBC比较以及连接池的技术

字体大小: 中小 标准 ->行高大小: 标准
     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相对与JDBC来说是他的灵活性,程序员不需要关心“具体的数据库后台是什么?JDBC驱动程序是什么?JDBC URL格式是什么?访问数据库的用户名和口令是什么?”等等这些问题,程序员编写的程序应该没有对 JDBC 驱动程序的引用,没有服务器名称,没有用户名称或口令 —— 甚至没有数据库池或连接管理。而是把这些问题交给J2EE容器来配置和管理,程序员只需要对这些配置和管理进行引用即可。
 
理解连接池
 
连接池是创建和管理多个连接的一种技术,这些连接可被需要使用它们的任何线程使用。连接池技术基于下述事实:对于大多数应用程序,当它们正在处理通常需要数毫秒完成的事务时,仅需要能够访问JDBC连接的1个线程。未处理事务时,连接处于闲置状态。使用连接池,允许其他线程使用闲置连接来执行有用的任务。
 
事实上,当某一线程需要用JDBC在MySQL或其他数据库上执行操作时,需要用到由连接池提供的连接。使用连接完成线程后,线程会将连接返回给连接池,以便该连接能够被其他需要使用连接的线程使用。
 
从连接池“借出”连接时,该连接仅供请求它的线程使用。从编程观点看,其效果等同于每次需要JDBC连接时调用DriverManager.getConnection(),但是,采用连接池技术,可通过使用新的或已有的连接结束线程。
 
连接池技术能显著增加Java应用程序的性能,同时还能降低资源使用率。连接池技术的主要优点包括:
 
·         缩短了连接创建时间
 
与其他数据库相比,MySQL提供了快速的连接设置功能,连接时间通常不是问题,但创建新的JDBC连接仍会导致联网操作和一定的IDBC驱动开销,如果这类连接是“循环”使用的,使用该方式,可避免这类不利因素。
 
·         简化的编程模型
 
使用连接池技术时,每个单独线程能够像创建了自己的JDBC连接那样进行操作,从而允许使用直接的JDBC编程技术。
 
·         受控的资源使用
 
如果不使用连接池技术,而是在每次需要时为线程创建新的连接,那么应用程序的资源使用将十分浪费,而且在负载较重的情况下会导致无法预期的结果。
 
注意,与MySQL的每个连接均会在客户端和服务器端造成一定的开销(每寸、CPU、关联转换等)。每个连接均会对应用程序和MySQL服务器的可用资源带来一定的限制。无论连接是否执行任何有用的任务,仍将使用这些资源中的相当一部分。
 
连接池能够使性能最大化,同时还能将资源利用控制在一定的水平之下,如果超过该水平,应用程序将崩溃而不仅仅是变慢。
 
幸运的是,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.
 
         *
 
         * 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) {
 
                try {
 
                    conn.close();
 
                } catch (sqlexception sqlex) {
 
                    // 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等工具创建负载测试脚本,并对应用程序进行负载测试。
 
确定出发点的一种简单方法是,将连接池的最大连接数配置为“无限”,运行负载测试,并测量最大的并发连接数。随后,应进行反向操作,确定出使应用程序具有最佳性能的连接池的最小和最大值。

此文章由 http://www.ositren.com 收集整理 ,地址为: http://www.ositren.com/htmls/68794.html