下载安卓APP箭头
箭头给我发消息

客服QQ:3315713922

数据库连接池

作者:课课家教育     来源: http://www.kokojia.com点击数:770发布时间: 2017-06-05 15:00:14

标签: 数据库数据库基础数据库连接

  我们在操作数据库的时候首先最重要的就是获取数据库的连接,只有获取了连接才能有后面对数据库的一系列操作。但是获取连接的过程是非常消耗数据库资源的,并且也非常耗时,这一点看看TCP三次握手取得连接也可以想象的到。多次获取连接比长连接还要耗费资源,因此在会大量操作数据库的情况下,减少数据库创建连接的次数是能极大地优化数据库的性能。

      如果不用连接池,则数据库为每一个用户的来访创建一个链接,虽然数据库本身在安装的时候会指定最大连接数,但是我们说过资源的耗费和耗时其实是在这些有限连接的不断创建和销毁的循环中。如下图所示:

数据库连接池_数据库_数据库基础_数据库连接_课课家教育

  一、数据库连接池(DataSource)

  数据库连接池,也称为数据源。是在应用开始前就将数据库的连接创建多个而不销毁,同时管理起来,犹如放在一个池子里,那么只要用户来访问数据库,则不在是直接通过数据库获取连接,而是从连接池中获取连接,再通过连接操纵数据库,最后再将连接返回给连接池,以便别的访问再从池子中获取连接进行操作。

一、数据库连接池(DataSource)    数据库连接池,也称为数据源。是在应用开始前就将数据库的连接创建多个而不销毁,同时管理起来,犹如放在一个池子里,那么只要用户来访问数据库,则不在是直接通过数据库获取连接,而是从连接池中获取连接,再通过连接操纵数据库,最后再将连接返回给连接池,以便别的访问再从池子中获取连接进行操作。

      数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数来设定的。无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。

  数据库连接池的最小连接数和最大连接数的设置要考虑到以下几个因素:

  ①最小连接数:是连接池一直保持的数据库连接,所以如果应用程序对数据库连接的使用量不大,将会有大量的数据库连接资源被浪费。

  ②最大连接数:是连接池能申请的最大连接数,如果数据库连接请求超过次数,后面的数据库连接请求将被加入到等待队列中,这会影响以后的数据库操作。

  ③如果最小连接数与最大连接数相差很大:那么最先连接请求将会获利,之后超过最小连接数量的连接请求等价于建立一个新的数据库连接。不过,这些大于最小连接数的数据库连接在使用完不会马上被释放,他将被放到连接池中等待重复使用或是空间超时后被释放。

  二、使用数据库连接池的意义

  1、java应用程序访问数据库的基本原理

  在Java语言中,JDBC(JavaDataBaseConnection)是应用程序与数据库沟通的桥梁,即Java语言通过JDBC技术访问数据库。JDBC是一种“开放”的方案,它为数据库应用开发人员﹑数据库前台工具开发人员提供了一种标准的应用程序设计接口,使开发人员可以用纯Java语言编写完整的数据库应用程序。JDBC提供两种API,分别是面向开发人员的API和面向底层的JDBC驱动程序API,底层主要通过直接的JDBC驱动和JDBC-ODBC桥驱动实现与数据库的连接。

  一般来说,Java应用程序访问数据库的过程是:

  ①装载数据库驱动程序;

  ②通过JDBC建立数据库连接;

  ③访问数据库,执行SQL语句;

  ④断开数据库连接。

  JDBC作为一种数据库访问技术,具有简单易用的优点。但使用这种模式进行Web应用程序开发,存在很多问题:首先,每一次Web请求都要建立一次数据库连接。建立连接是一个费时的活动,每次都得花费0.05s~1s的时间,而且系统还要分配内存资源。这个时间对于一次或几次数据库操作,或许感觉不出系统有多大的开销。可是对于现在的Web应用,尤其是大型电子商务网站,同时有几百人甚至几千人在线是很正常的事。在这种情况下,频繁的进行数据库连接操作势必占用很多的系统资源,网站的响应速度必定下降,严重的甚至会造成服务器的崩溃。不是危言耸听,这就是制约某些电子商务网站发展的技术瓶颈问题。其次,对于每一次数据库连接,使用完后都得断开。否则,如果程序出现异常而未能关闭,将会导致数据库系统中的内存泄漏,最终将不得不重启数据库。还有,这种开发不能控制被创建的连接对象数,系统资源会被毫无顾及的分配出去,如连接过多,也可能导致内存泄漏,服务器崩溃。

  2、数据库连接池(connectionpool)

  1>基本概念及原理

  由上面的分析可以看出,问题的根源就在于对数据库连接资源的低效管理。我们知道,对于共享资源,有一个很著名的设计模式:资源池(ResourcePool)。该模式正是为了解决资源的频繁分配﹑释放所造成的问题。为解决上述问题,可以采用数据库连接池技术。数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。我们可以通过设定连接池最大连接数来防止系统无尽的与数据库连接。更为重要的是我们可以通过连接池的管理机制监视数据库的连接的数量﹑使用情况,为系统开发﹑测试及性能调整提供依据。

  2>服务器自带的连接池

  JDBC的API中没有提供连接池的方法。一些大型的WEB应用服务器如BEA的WebLogic和IBM的WebSphere等提供了连接池的机制,但是必须有其第三方的专用类方法支持连接池的用法。

  三、使用数据库连接池的关键点

  1、并发问题

  为了使连接管理服务具有最大的通用性,必须考虑多线程环境,即并发问题。这个问题相对比较好解决,因为各个语言自身提供了对并发管理的支持像java,c#等等,使用synchronized(java)lock(C#)关键字即可确保线程是同步的。使用方法可以参考,相关文献。

  2、事务处理

  我们知道,事务具有原子性,此时要求对数据库的操作符合“ALL-ALL-NOTHING”原则,即对于一组SQL语句要么全做,要么全不做。

  我们知道当2个线程共用一个连接Connection对象,而且各自都有自己的事务要处理时候,对于连接池是一个很头疼的问题,因为即使Connection类提供了相应的事务支持,可是我们仍然不能确定那个数据库操作是对应那个事务的,这是由于我们有2个线程都在进行事务操作而引起的。为此我们可以使用每一个事务独占一个连接来实现,虽然这种方法有点浪费连接池资源但是可以大大降低事务管理的复杂性。

  3、连接池的分配与释放

  连接池的分配与释放,对系统的性能有很大的影响。合理的分配与释放,可以提高连接的复用度,从而降低建立新连接的开销,同时还可以加快用户的访问速度。

  对于连接的管理可使用一个List。即把已经创建的连接都放入List中去统一管理。每当用户请求一个连接时,系统检查这个List中有没有可以分配的连接。如果有就把那个最合适的连接分配给他(如何能找到最合适的连接文章将在关键议题中指出);如果没有就抛出一个异常给用户,List中连接是否可以被分配由一个线程来专门管理捎后我会介绍这个线程的具体实现。

  4、连接池的配置与维护

  连接池中到底应该放置多少连接,才能使系统的性能最佳?系统可采取设置最小连接数(minConnection)和最大连接数(maxConnection)等参数来控制连接池中的连接。比方说,最小连接数是系统启动时连接池所创建的连接数。如果创建过多,则系统启动就慢,但创建后系统的响应速度会很快;如果创建过少,则系统启动的很快,响应起来却慢。这样,可以在开发时,设置较小的最小连接数,开发起来会快,而在系统实际使用时设置较大的,因为这样对访问客户来说速度会快些。最大连接数是连接池中允许连接的最大数目,具体设置多少,要看系统的访问量,可通过软件需求上得到。

  如何确保连接池中的最小连接数呢?有动态和静态两种策略。动态即每隔一定时间就对连接池进行检测,如果发现连接数量小于最小连接数,则补充相应数量的新连接,以保证连接池的正常运转。静态是发现空闲连接不够时再去检查。

  5、引用计数

  再分配、释放策略对于有效复用连接非常重要,我们采用的方法也是采用了一个很有名的设计模式:ReferenceCounting(引用记数)。该模式在复用资源方面用的非常广泛,我们把该方法运用到对于连接的分配释放上。每一个数据库连接,保留一个引用记数,用来记录该连接的使用者的个数。具体的实现上,我们对Connection类进行进一步包装来实现引用记数。被包装的Connection类我们提供2个方法来实现引用记数的操作,一个是Repeat(被分配出去)Remove(被释放回来);然后利用RepeatNow属性来确定当前被引用多少,具体是哪个用户引用了该连接将在连接池中登记;最后提供IsRepeat属性来确定该连接是否可以使用引用记数技术。一旦一个连接被分配出去,那么就会对该连接的申请者进行登记,并且增加引用记数,当被释放回来时候就删除他已经登记的信息,同时减少一次引用记数。

  这样做有一个很大的好处,使得我们可以高效的使用连接,因为一旦所有连接都被分配出去,我们就可以根据相应的策略从使用池中挑选出一个已经正在使用的连接用来复用,而不是随意拿出一个连接去复用。

  四、使用数据库连接池的优势和其工作原理

  1、连接池的优势

  连接池用于创建和管理数据库连接的缓冲池技术,缓冲池中的连接可以被任何需要他们的线程使用。当一个线程需要用JDBC对一个数据库操作时,将从池中请求一个连接。当这个连接使用完毕后,将返回到连接池中,等待为其他的线程服务。

  连接池的主要优点有以下三个方面。

  第一、减少连接创建时间。连接池中的连接是已准备好的、可重复使用的,获取后可以直接访问数据库,因此减少了连接创建的次数和时间。

  第二、简化的编程模式。当使用连接池时,每一个单独的线程能够像创建一个自己的JDBC连接一样操作,允许用户直接使用JDBC编程技术。

  第三、控制资源的使用。如果不使用连接池,每次访问数据库都需要创建一个连接,这样系统的稳定性受系统连接需求影响很大,很容易产生资源浪费和高负载异常。连接池能够使性能最大化,将资源利用控制在一定的水平之下。连接池能控制池中的连接数量,增强了系统在大量用户应用时的稳定性。

  2、连接池的工作原理

  下面,简单的阐述下连接池的工作原理。

  连接池技术的核心思想是连接复用,通过建立一个数据库连接池以及一套连接使用、分配和管理策略,使得该连接池中的连接可以得到高效、安全的复用,避免了数据库连接频繁建立、关闭的开销。

  连接池的工作原理主要由三部分组成,分别为连接池的建立、连接池中连接的使用管理、连接池的关闭。

  第一、连接池的建立。一般在系统初始化时,连接池会根据系统配置建立,并在池中创建了几个连接对象,以便使用时能从连接池中获取。连接池中的连接不能随意创建和关闭,这样避免了连接随意建立和关闭造成的系统开销。Java中提供了很多容器类可以方便的构建连接池,例如Vector、Stack等。

  第二、连接池的管理。连接池管理策略是连接池机制的核心,连接池内连接的分配和释放对系统的性能有很大的影响。其管理策略是:

  当客户请求数据库连接时,首先查看连接池中是否有空闲连接,如果存在空闲连接,则将连接分配给客户使用;如果没有空闲连接,则查看当前所开的连接数是否已经达到最大连接数,如果没达到就重新创建一个连接给请求的客户;如果达到就按设定的最大等待时间进行等待,如果超出最大等待时间,则抛出异常给客户。

  当客户释放数据库连接时,先判断该连接的引用次数是否超过了规定值,如果超过就从连接池中删除该连接,否则保留为其他客户服务。

  该策略保证了数据库连接的有效复用,避免频繁的建立、释放连接所带来的系统资源开销。

  第三、连接池的关闭。当应用程序退出时,关闭连接池中所有的连接,释放连接池相关的资源,该过程正好与创建相反。

  使用JDBC编写自定义的数据库连接池(DataSource)

  要编写自定义的数据库连接池,必须要实现DataSource接口。

使用JDBC编写自定义的数据库连接池(DataSource)    要编写自定义的数据库连接池,必须要实现DataSource接口。

  之前我们创建连接Connection对象都是通过DriveManager驱动管理器来获取的,但这是直接使数据库为我们创建连接,而上图DataSource接口的API也说明了,我们要想获取连接的首选方法应该是通过DataSource接口来获取连接池中的连接。

  DataSource接口自身主要就两个方法,但是DataSource还继承了别的接口,因此如果要实现DataSource接口的话,还必须将其父类的方法均实现:

之前我们创建连接Connection对象都是通过DriveManager驱动管理器来获取的,但这是直接使数据库为我们创建连接,而上图DataSource接口的API也说明了,我们要想获取连接的首选方法应该是通过DataSource接口来获取连接池中的连接。    DataSource接口自身主要就两个方法,但是DataSource还继承了别的接口,因此如果要实现DataSource接口的话,还必须将其父类的方法均实现:

  因此我们在编写自己的数据库连接池类时,需要添加覆写多个未实现的方法,虽然我们也不会在这些方法中编写任何内容。

  我们要想实现自己定义的一个连接池,需要实现以下几个步骤:

  1.定义一个类,实现DataSource接口。

  2.在这个类的初始化方法(例如构造函数或者静态代码块)中,通过DriveManager驱动管理器构建多个连接,这个还是跟以前获取Connection对象一样的用法。这一步是因为我们要先从数据库获取连接,才能将这些连接保存,即将多次创建连接变为一次创建而使用长连接。

  3.将上面从数据库直接创建的连接存到LinkedList集合中,而这个集合就相当于一个池子,使用链表结构的集合有利于增删操作。

  4.这个自定义的类当然要实现DataSource接口中的方法,其中最重要的就是我们要覆盖getConnection()方法,这是给别的要操作数据库的方法提供Connection对象,所以这次要从刚才保存连接的LinkedList集合取出连接给别的方法(即从连接池中取出连接)。但是我们从集合取出给别的方法的又不能直接就是数据库提供的Connection对象(也就是刚才初始化存入集合中的Connection对象),因为最后必须要释放资源,而一旦直接调用数据库提供的Connection对象的close()方法则就是将该连接销毁了,因此我们通过集合(连接池)取出Connection对象应该进行功能增强,最后再在getConnection()方法返回出去给别的方法使用。而这一步也是整个步骤中最难的,也是最重要的一个知识点。

  以上的关键在于第4步,我们要返回的是一个即是Connection接口的实例对象,又不能因为调用close()方法而销毁了这个链接,而是调用close()方法能将该Connection接口的实例对象返回给集合中。因此我们必须要对Connection中的close()方法进行覆写。但如何对Connection的对象进行功能增强,主要有下面三种方法:

  ①编写一个Connection的子类,覆写close()方法。

  ②使用包装设计模式。

  ③使用动态代理。

  使用子类的方式不合理,且不说我们的Connection对象中封装了很多和数据库相关的信息,单是Connection接口就需要现实很多很多方法,所以这不实际。在本篇中我们使用包装设计模式来增强数据库直接提供的Connection对象,覆写close()方法,将其功能从销毁连接变为返回进集合中。关于包装设计模式请看《包装设计模式》。

  接下来我们将会在一个工程中按上面的步骤来简单地创建一个自定义的数据库连接池。

  ⑴创建一个JdbcPool类,同之前使用JDBC工具类(如《JDBC操作数据库的学习(2)》)一样,在初始化时就根据配置文件实现注册驱动,获取连接等等操作。这里我们创建一个初始连接池数为10个的连接池。

  配置文件内容如下:

 接下来我们将会在一个工程中按上面的步骤来简单地创建一个自定义的数据库连接池。    ⑴创建一个JdbcPool类,同之前使用JDBC工具类(如《JDBC操作数据库的学习(2)》)一样,在初始化时就根据配置文件实现注册驱动,获取连接等等操作。这里我们创建一个初始连接池数为10个的连接池。    配置文件内容如下:

 接下来我们将会在一个工程中按上面的步骤来简单地创建一个自定义的数据库连接池。    ⑴创建一个JdbcPool类,同之前使用JDBC工具类(如《JDBC操作数据库的学习(2)》)一样,在初始化时就根据配置文件实现注册驱动,获取连接等等操作。这里我们创建一个初始连接池数为10个的连接池。    配置文件内容如下:

  以上就是一个简单的使用JDBC来实现一个数据库连接池的代码。在上面的代码中,我们在该类(JdbcPool)的初始化时(静态代码块里),先通过驱动管理器获取了十个连接,并将数据库提供的连接Connection对象存入集合也就是我们说的池中。

  而别的方法需要通过JdbcPool类的getConnection方法来获取池中的连接,但是我们通过一个包装类,同时在上面也是内部类,将池中的连接取出,并做了包装,覆写了close方法,最后再返回出去,这时候别的方法获取的并不是数据库直接提供的连接,而是我们自己包装过的类,这个包装类除了close方法不同外,其他还是一样的和原来数据库提供的连接具有相同的方法,以为就是在调用原来连接的方法。

  使用包装设计模式虽然能满足我们的需求,但是如果要包装的接口方法过多,例如Connection接口,而我们只想覆写其中一两个方法,则程序会造成极大的冗余,因此最佳的方式应该是使用动态代理。

  小编结语:

  更多内容尽在课课家教育!

赞(27)
踩(0)
分享到:
华为认证网络工程师 HCIE直播课视频教程