谈谈数据库链接池的原理

 此次咱们采起技术演进的方式来谈谈数据库链接池的技术出现过程及其原理,以及当下最流行的开源数据库链接池jar包。java

一.早期咱们怎么进行数据库操做web

       1.原理:通常来讲,java应用程序访问数据库的过程是:sql

   ①装载数据库驱动程序;数据库

   ②经过jdbc创建数据库链接;apache

   ③访问数据库,执行sql语句;设计模式

   ④断开数据库链接。服务器

       2.代码 多线程

       // 查询全部用户并发

 

[java]  view plain  copy
 
  1. Public void FindAllUsers(){  
  2.        //一、装载sqlserver驱动对象  
  3.        DriverManager.registerDriver(new SQLServerDriver());               
  4.        //二、经过JDBC创建数据库链接  
  5.        Connection con =DriverManager.getConnection("jdbc:sqlserver://192.168.2.6:1433;DatabaseName=customer", "sa", "123");              
  6.        //三、建立状态  
  7.        Statement state =con.createStatement();             
  8.        //四、查询数据库并返回结果  
  9.        ResultSet result =state.executeQuery("select * from users");             
  10.        //五、输出查询结果  
  11.        while(result.next()){  
  12.               System.out.println(result.getString("email"));  
  13.        }              
  14.        //六、断开数据库链接  
  15.        result.close();  
  16.        state.close();  
  17.        con.close();  
  18.  }  

 

3.分析oracle

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

       上述的用户查询案例,若是同时有1000人访问,就会不断的有数据库链接、断开操做:

 

 

       经过上面的分析,咱们能够看出来,“数据库链接”是一种稀缺的资源,为了保障网站的正常使用,应该对其进行妥善管理。其实咱们查询完数据库后,若是不关闭链接,而是暂时存放起来,当别人使用时,把这个链接给他们使用。就避免了一次创建数据库链接和断开的操做时间消耗。原理以下:

二. 技术演进出来的数据库链接池

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

       咱们本身尝试开发一个链接池,来为上面的查询业务提供数据库链接服务:

       ①   编写class 实现DataSource 接口

       ②   在class构造器一次性建立10个链接,将链接保存LinkedList中

       ③   实现getConnection  从 LinkedList中返回一个链接

       ④   提供将链接放回链接池中方法

 

       一、链接池代码       

[java]  view plain  copy
 
  1. public class MyDataSource implements DataSource {  
  2.           //链表 --- 实现栈结构  
  3.           privateLinkedList<Connection> dataSources = new LinkedList<Connection>();  
  4.   
  5.           //初始化链接数量  
  6.           publicMyDataSource() {  
  7.                  //一次性建立10个链接  
  8.                  for(int i = 0; i < 10; i++) {  
  9.                         try {  
  10.                            //一、装载sqlserver驱动对象  
  11.                            DriverManager.registerDriver(new SQLServerDriver());  
  12.                            //二、经过JDBC创建数据库链接  
  13.                            Connection con =DriverManager.getConnection(  
  14.                               "jdbc:sqlserver://192.168.2.6:1433;DatabaseName=customer", "sa", "123");  
  15.                            //三、将链接加入链接池中  
  16.                            dataSources.add(con);  
  17.                         } catch (Exception e) {  
  18.                            e.printStackTrace();  
  19.                         }  
  20.                  }  
  21.           }  
  22.   
  23.           @Override  
  24.           publicConnection getConnection() throws SQLException {  
  25.                  //取出链接池中一个链接  
  26.                  finalConnection conn = dataSources.removeFirst(); // 删除第一个链接返回  
  27.                  returnconn;  
  28.           }  
  29.   
  30.           //将链接放回链接池  
  31.           publicvoid releaseConnection(Connection conn) {  
  32.                  dataSources.add(conn);  
  33.                  }  
  34.    }  

 

       二、使用链接池重构咱们的用户查询函数       

[java]  view plain  copy
 
  1. //查询全部用户  
  2. Public void FindAllUsers(){  
  3.        //一、使用链接池创建数据库链接  
  4.        MyDataSource dataSource = new MyDataSource();  
  5.        Connection conn =dataSource.getConnection();          
  6.        //二、建立状态  
  7.        Statement state =con.createStatement();             
  8.        //三、查询数据库并返回结果  
  9.        ResultSet result =state.executeQuery("select * from users");             
  10.        //四、输出查询结果  
  11.        while(result.next()){  
  12.               System.out.println(result.getString("email"));  
  13.        }              
  14.        //五、断开数据库链接  
  15.        result.close();  
  16.        state.close();  
  17.        //六、归还数据库链接给链接池  
  18.        dataSource.releaseConnection(conn);  
  19.  }  

 

 

       这就是数据库链接池的原理,它大大提供了数据库链接的利用率,减少了内存吞吐的开销。咱们在开发过程当中,就不须要再关心数据库链接的问题,天然有数据库链接池帮助咱们处理,这回放心了吧。但链接池须要考虑的问题不只仅如此,下面咱们就看看还有哪些问题须要考虑。

三.链接池还要考虑更多的问题

       一、并发问题

       为了使链接管理服务具备最大的通用性,必须考虑多线程环境,即并发问题。这个问题相对比较好解决,由于java语言自身提供了对并发管理的支持,使用synchronized关键字便可确保线程是同步的。使用方法为直接在类方法前面加上synchronized关键字,如:

      publicsynchronized connection getconnection()

 

       二、多数据库服务器和多用户

       对于大型的企业级应用,经常须要同时链接不一样的数据库(如链接oracle和sybase)。如何链接不一样的数据库呢?咱们采用的策略是:设计一个符合单例模式的链接池管理类,在链接池管理类的惟一实例被建立时读取一个资源文件,其中资源文件中存放着多个数据库的url地址等信息。根据资源文件提供的信息,建立多个链接池类的实例,每个实例都是一个特定数据库的链接池。链接池管理类实例为每一个链接池实例取一个名字,经过不一样的名字来管理不一样的链接池。

       对于同一个数据库有多个用户使用不一样的名称和密码访问的状况,也能够经过资源文件处理,即在资源文件中设置多个具备相同url地址,但具备不一样用户名和密码的数据库链接信息。

 

       三、事务处理

       咱们知道,事务具备原子性,此时要求对数据库的操做符合“all-all-nothing”原则即对于一组sql语句要么全作,要么全不作。

       在java语言中,connection类自己提供了对事务的支持,能够经过设置connection的autocommit属性为false 而后显式的调用commit或rollback方法来实现。但要高效的进行connection复用,就必须提供相应的事务支持机制。可采用每个事务独占一个链接来实现,这种方法能够大大下降事务管理的复杂性。

 

       四、链接池的分配与释放

       链接池的分配与释放,对系统的性能有很大的影响。合理的分配与释放,能够提升链接的复用度,从而下降创建新链接的开销,同时还能够加快用户的访问速度。

       对于链接的管理可以使用空闲池。即把已经建立但还没有分配出去的链接按建立时间存放到一个空闲池中。每当用户请求一个链接时,系统首先检查空闲池内有没有空闲链接。若是有就把创建时间最长(经过容器的顺序存放实现)的那个链接分配给他(实际是先作链接是否有效的判断,若是可用就分配给用户,如不可用就把这个链接从空闲池删掉,从新检测空闲池是否还有链接);若是没有则检查当前所开链接池是否达到链接池所容许的最大链接数(maxconn)若是没有达到,就新建一个链接,若是已经达到,就等待必定的时间(timeout)。若是在等待的时间内有链接被释放出来就能够把这个链接分配给等待的用户,若是等待时间超过预约时间timeout 则返回空值(null)。系统对已经分配出去正在使用的链接只作计数,当使用完后再返还给空闲池。对于空闲链接的状态,可开辟专门的线程定时检测,这样会花费必定的系统开销,但能够保证较快的响应速度。也可采起不开辟专门线程,只是在分配前检测的方法。

 

       五、链接池的配置与维护

       链接池中到底应该放置多少链接,才能使系统的性能最佳?系统可采起设置最小链接数(minconn)和最大链接数(maxconn)来控制链接池中的链接。最小链接数是系统启动时链接池所建立的链接数。若是建立过多,则系统启动就慢,但建立后系统的响应速度会很快;若是建立过少,则系统启动的很快,响应起来却慢。这样,能够在开发时,设置较小的最小链接数,开发起来会快,而在系统实际使用时设置较大的,由于这样对访问客户来讲速度会快些。最大链接数是链接池中容许链接的最大数目,具体设置多少,要看系统的访问量,可经过反复测试,找到最佳点。

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

四.实际开发中有成熟的开源链接池供咱们使用

       理解了链接池的原理就能够了,没有必要什么都从头写一遍,那样会花费不少时间,而且性能及稳定性也不必定知足要求。事实上,已经存在不少流行的性能优良的第三方数据库链接池jar包供咱们使用。如:

       1.Apache commons-dbcp 链接池

        下载:http://commons.apache.org/proper/commons-dbcp/

 

       2.c3p0 数据库链接池

        下载:http://sourceforge.net/projects/c3p0/

相关文章
相关标签/搜索