讲真,你真的懂JDBC吗?

讲真,你真的懂JDBC吗?

2017-10-19 07:12 王新栋  0   0  阅读 4


作者介绍

王新栋从事京麦平台的架构设计与开发工作。熟悉各种开源软件架构,在web开发,架构优化上有较丰富的实战经历。有多年在NIO领域的设计、开发经验,对HTTP、TCP长连接技术有深入研究与领悟,目前主要致力于移动与PC平台网关技术的优化与实现。


数据库连接池在J2EE领域是一个不可缺失的组件,尽管Druid越来越流行,但是DBCP作为一个老牌的数据库连接池,一直在企业系统中默默奉献着自己。比如大部分系统还都是使用DBCP,那么我们还是很有必要对DBCP有一个熟悉的认识。


鉴于这样的需求,我根据相关资料,并结合自己的认知重新做了一个梳理,一来自己可以在以后的工作中回过头来温习,二来也希望能够帮助其它同学对DBCP以及涉及到的相关概念和知识(像超时机制、连接池原理等)有一个了解。众所周知,操作一个数据库的流程为:创建数据源,获得链接,构造statement,执行请求,下面我们逐步梳理总结。


一、相关概念复习 


在谈DBCP之前我们先来复习一下几个相关的概念:


  1   JNDI 


Java Naming and Directory Interface (JNDI)JNDI API被用于执行名字和目录服务。它提供了一致的模型来存取和操作企业级的资源。JNDI的api位于javax.naming包中,它的作用是可以把对象放到一个容器中(JNDI容器),Java对象在这个容器中都有一个名称,程序则可以通过这个名称来获取对象,例如下面这样:



  2   JDBC 



Java数据库连接(Java Database Connectivity,简称JDBC),是Java语言中用来规范客户端应用程序(比如Web应用程序等如何访问关系型数据库的应用程序接口),提供了诸如查询和更新数据库中数据的方法。


JDBC驱动程序一共有四种类型:

  • 类型1-JDBC-ODBC桥

  • 类型2-本地API驱动

  • 类型3-网络协议驱动

  • 类型4-本地协议驱动


我们常用的是类型4-本地协议驱动,这种类型的驱动使用socket链接,直接在客户端和数据库之间进行通信。


优点是1-访问速度快 2-最直接,最纯粹的JAVA实现。
缺点是1-需要每个数据库厂商提供自己的JDBC驱动。2-需要针对不同的数据库使用不同的驱动程序。

JDBC的API在jdk的java.sql包中,扩展的内容在javax.sql包中。主要包括(斜体代表接口,需驱动程序提供者来具体实现):


  • DriverManager:负责加载各种不同驱动程序(Driver),并根据不同的请求,向调用者返回相应的数据库连接(Connection)。

  • Driver:驱动程序,会将自身加载到DriverManager中去,并处理相应的请求并返回相应的数据库连接(Connection)。

  • Connection:数据库连接,负责进行与数据库间的通讯,SQL执行以及事务处理都是在某个特定Connection环境中进行的。可以产生用以执行SQL的Statement。

  • Statement:用以执行SQL查询和更新(针对静态SQL语句和单次执行)。

  • PreparedStatement:用以执行包含动态参数的SQL查询和更新(在服务器端编译,允许重复执行以提高效率)。

  • CallableStatement:用以调用数据库中的存储过程。

  • SQLException:代表在数据库连接的创建和关闭和SQL语句的执行过程中发生了例外情况(即错误)。


  3   DBCP数据库连接池和JDBC之间的关系 


数据库连接池负责创建(通过JDBC API)、管理、销毁数据库的连接。应用程序可以从数据库连接池中重复使用一个现有的连接,而不是重新创建一个。连接池,common-pool中的GenericObjectPool它负责缓存和管理连接;连接,这是是指PoolableConnection;连接池和连接一对多的关系。池化技术是通过commons-pool来实现的,每个连接是一个对象,换言之,是对象池的使用与管理。DBCP连接池是基于commons-pool这种对象池来实现的。


二、commons-pool的理解 


Apache commons-pool是一种对象池技术,我们使用的很多涉及池的场景一般都是基于该组件来实现的,DBCP数据库连接池也是基于commons-pool来实现的,因此我们先来了解下这种对象池技术。下图是对象池的对象生命周期流程图。



三、DBCP核心类图及序列图 


 BasicDataSource.java



 ConnectionFactory.java



 PoolingDataSource.java



 PoolingConnection.java



 Delegating.java



 AbandonedObjectPool.java



 创建数据源createDataSource



 创建连接getConnection



 创建statement prepareStatement




四、DBCP配置及使用 


DBCP是Apache下的一个开源数据库连接池,我们在使用时需要两个JAR文件,分别是commons-dbcp.jar(连接池的实现)和commons-pool.jar(连接池实现的依赖库),不过我们在使用的时候只需要引入下面mvaen坐标,commons-pool是在commons-dbcp里面隐含引用了。


注意一点,就是从1.x升级到2.x的时候,由于DBCP的包路径已经变了,需要升级者修改局部代码。


    commons-dbcp

    commons-dbcp

    2.2


DBCP可以在应用程序中独立的使用,也可以与web应用服务器整合使用。


  1   Tomcat中使用 


比如Tomcat的连接池就是采用该连接池来实现的。如下:



  2   应用程序中独立使用 



更多配置请参照

https://commons.apache.org/proper/commons-dbcp/configuration.html


五、连接超时机制 


对网络资源访问时,超时设置是必须的。没有超时的保护,一旦依赖资源发生故障或者网络故障,就会引起线程堆积,甚至发生雪崩。


  1   超时层级 



从这张图中我们也能够看出DBCP并不参与数据库超时的处理,它只负责管理连接。根据上图我们可以看到超时有一个依赖层级,上层超时依赖下层超时。依次为:事务超时->Statement超时->JDBC Driver socket超时->操作系统超时。


  事务超时


事务是应用层级的概念,我们知道事务是有一组SQL执行单元组成的。那么事务超时的时间阈值,实际是Statement超时N个需要执行的Statement数量。比如一个事务里面有3条Statement,每条Statement的执行时间是50MS,其它业务上的逻辑执行时间+框架执行时间未100ms,那么最终事务的超时时间为:350+100=250ms。


  statement超时


用来限制SQL语句的执行时间,通过setQueryTimeout(int timeout)来设置,不过现在大都是ibatis了,可以通过 SqlMapConfig.xml 中的 setting 属性defaultStatementTimeout 来设置全局的 statement 超时缺省值,还可以在每个sql.xml文件中,根据业务实际需要来设置