日常啰嗦
终于回到既定轨道上了,这一篇讲讲数据库连接池的相关知识,线程池以后有机会再结合项目单独写篇文章(自己给自己挖坑,不知道什么时候能填上),从这一篇文章开始到本阶段结束的文章都会围绕数据库和dao层的优化去写,本篇是一个开始。本文会介绍连接池技术并对比目前比较流行的java连接池技术,之后,会把druid整合到项目中来,将技术方案落地,实际整合到项目中,让技术能为我所用。
使用连接池的原因及部分连接池介绍
jdbc的demo
```
//第一步,注册驱动程序
//com.MySQL.jdbc.Driver
Class.forName("数据库驱动的完整类名");
//第二步,获取一个数据库的连接
Connection conn = DriverManager.getConnection("数据库地址","用户名","密码");
//第三步,创建一个会话
Statement stmt=conn.createStatement();
//第四步,执行SQL语句
stmt.executeUpdate("SQL语句");
//或者查询记录
ResultSet rs = stmt.executeQuery("查询记录的SQL语句");
//第五步,对查询的结果进行处理
while(rs.next()){
//操作
}
//第六步,关闭连接
rs.close();
stmt.close();
conn.close();
```
对上面几行代码,大家不会陌生,这可能是我们初学jdbc连接时最熟悉的代码了,虽然现在可能用到了一些数据层ORM框架,但是底层实现依然如同上面代码一样,只是做了一些封装而已。这种方式也有一些不足,在与mysql进行数据交互时每次都需要新建connection资源,用完后关闭掉Connection资源,这种做法是非常浪费资源的,如果抬杠的话,可能有人会说,我就喜欢这种方式,我服务器配置足够好,我一点都不担心什么资源不资源,那你牛逼。
浪费资源这种说法是相对而言的,如果在小型项目中或者项目与数据库的交互不那么频繁的话,数据库连接的创建与关闭也不见得会把资源浪费多少,亦或者在项目启动时期,我们可能只考虑功能实现,就直接copy一份现成的数据库集成代码过来用,这种做法都是很正常的现象,本阶段的内容主要是项目优化,那么关注点肯定就不是项目初始时期,也不去讨论硬件配置有多好,而是针对目前代码中的不足进行优化,找到一个相对较好的优化方案,并落实到项目中去,今天我们讲的优化方案就是使用连接池技术代替目前与数据库的交互方式。
为什么在连接数据库时要使用连接池?
数据库连接是一种关键的有限的昂贵的资源,一个数据库连接对象均对应一个物理数据库连接,每次操作都打开一个物理连接,使用完都关闭连接,这样造成系统的性能低下。
数据库连接池的解决方案是在应用程序启动时建立足够的数据库连接,并将这些连接组成一个连接池,简单的说,就是在一个"池"里放了好多半成品的数据库连接对象,由应用程序动态地对池中的连接进行申请、使用和释放等操作。
连接池技术尽可能多地重用了消耗内存地资源,大大节省了内存,提高了服务器的服务效率,减少了程序与数据库交互时的部分开销,显著的改善应用程序的性能,通过使用连接池,提高了程序运行效率,同时,我们可以通过其自身的管理机制来监视数据库连接的数量、使用情况等。
连接池的工作原理
连接池技术的核心思想是连接复用(也是我们在前一篇文章中提到的资源重用),通过建立一个数据库连接池以及一套连接使用、分配和管理策略,使得该连接池中的连接可以得到高效、安全的复用,避免了数据库连接频繁建立、关闭的开销。
**连接池的工作原理主要由三部分组成,分别为连接池的建立、连接池中连接的使用管理、连接池的关闭:**
- 第一、连接池的建立。一般在系统初始化时,连接池会根据系统配置建立,并在池中创建了几个连接对象,以便使用时能从连接池中获取。连接池中的连接不能随意创建和关闭,这样避免了连接随意建立和关闭造成的系统开销。Java中提供了很多容器类可以方便的构建连接池,例如Vector、Stack等。
- 第二、连接池的管理。连接池管理策略是连接池机制的核心,连接池内连接的分配和释放对系统的性能有很大的影响。其管理策略是:
- 当客户请求数据库连接时,首先查看连接池中是否有空闲连接,如果存在空闲连接,则将连接分配给客户使用;
- 如果没有空闲连接,则查看当前所开的连接数是否已经达到最大连接数,如果没达到就重新创建一个连接给请求的客户;
- 如果达到就按设定的最大等待时间进行等待,如果超出最大等待时间,则抛出异常给客户。
- 当客户释放数据库连接时,先判断该连接的引用次数是否超过了规定值,如果超过就从连接池中删除该连接,否则保留为其他客户服务。
该策略保证了数据库连接的有效复用,避免频繁的建立、释放连接所带来的系统资源开销。
- 第三、连接池的关闭。当应用程序退出时,关闭连接池中所有的连接,释放连接池相关的资源,该过程正好与创建相反。
连接池的优点及流行的连接池技术
对于连接池的优点,通过前文描述,我们也能得出以下结论:
- **减少连接创建时间。**连接池中的连接是已准备好的、可重复使用的,获取后可以直接访问数据库,因此减少了连接创建的次数和时间。
- **简化的编程模式。**当使用连接池时,每一个单独的线程能够像创建一个自己的JDBC连接一样操作,允许用户直接使用JDBC编程技术。
- **控制资源的使用。**如果不使用连接池,每次访问数据库都需要创建一个连接,这样系统的稳定性受系统连接需求影响很大,很容易产生资源浪费和高负载异常。连接池能够使性能最大化,将资源利用控制在一定的水平之下。连接池能控制池中的连接数量,增强了系统在大流量冲击下的稳定性。
流行的Java连接池:
- **C3P0**是一个开放源代码的JDBC连接池,它在lib目录中与Hibernate一起发布,包括了实现jdbc3和jdbc2扩展规范说明的Connection 和Statement 池的DataSources 对象。
- **DBCP** (Database Connection Pool)是一个依赖Jakarta commons-pool对象池机制的数据库连接池,Tomcat的数据源使用的就是DBCP。目前 DBCP 有两个版本分别是 1.3 和 1.4。1.3 版本对应的是 JDK 1.4-1.5 和 JDBC 3,而1.4 版本对应 JDK 1.6 和 JDBC 4。因此在选择版本的时候要看看你用的是什么 JDK 版本了,功能上倒是没有什么区别。
- **Proxool**是一个Java SQL Driver驱动程序,提供了对你选择的其它类型的驱动程序的连接池封装。可以非常简单的移植到现存的代码中。完全可配置。快速,成熟,健壮。可以透明地为你现存的JDBC驱动程序增加连接池功能
- **Druid**是阿里开源的一个数据库连接池技术,号称是目前最好的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池,包括DBCP、C3P0、BoneCP、Proxool、JBoss DataSource。Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。
对比下来,最终选择了Druid连接池,接下来也会将Druid技术整合到目前的项目中去,C3P0和DBCP都用过,也碰到一些问题,总体来说,功能中规中矩,比直接操作jdbc方式要好的多,但是对比与Druid的话就有些不足了,因为Druid是在目前市面上流行的连接池技术的基础上开发出来的,你有的Druid有,你没有的Druid也能提供,**Druid不仅仅是一个高效可管理的数据库连接池,它还有一套基于Filter-Chain模式的插件体系,也内置SQLParser功能,同时还能监控数据库访问性能,可以作为监控来使用,总结起来就是高效、功能强大、可扩展性好。**
总结:目前的问题及解决方案
目前ssm-demo项目中与mysql服务器的交互使用的是Spring自带的一个工具类,**DriverManagerDataSource**,配置文件如下:
```
```
DriverManagerDataSource建立连接的作法是只要有连接就新建一个connection,根本没有连接池的作用,也就是说文章前面所提到的资源消耗的弊端还是存在的,但是我们觉察不出来,感觉项目也挺正常的。这是因为目前网站的访问量较小,与mysql数据库的交互不频繁,由于访问量小,对后端的请求就少,因此mysql查询就少,压力也不会大,项目体量及访问总量都很小,就更别提数据库的QPS了,根本不值一提,也就是说现有的网站形势下,根本不会对mysql数据库产生任何的压力,根本不会有死锁的产生,根本不会有事务锁的产生,根本不会有数据库资源耗尽情况的产生,也根本不会有数据库服务器崩掉的产生.....
但是如果网站的访问量大了起来,功能丰富了起来,用户访问量增长了起来,是目前的10000倍、100000倍甚至更大的情况下,各种问题就随之而来了,当然,这么多问题出现了,我们是不是修改了数据连接池就好了?肯定不是,数据库连接池仅仅解决了数据层的部分问题,对性能有一部分的提升,它不能解决掉网站演进过程中的各种问题,别想太多,因为过程中会出现各种各样的问题,项目也会暴露出各个方面的不足,前端、后端、运维、DBA、架构....等等维度都有可能出现问题,需要不同的方案和不同的技术来优化,不要想着一劳永逸。
OK,可能有点扯远了,还是说回到连接池,下一篇文章会介绍阿里的Druid连接池技术并将其整合到项目中,待续。