`
jxxms
  • 浏览: 104713 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论
阅读更多

-
1. 引言

  近年来,随着Internet/Intranet建网技术的飞速发展和在世界范围内的迅速普及,计算机

  应用程序已从传统的桌面应用转到Web应用。基于B/S(Browser/Server)架构的3层开发模式逐渐取代C/S(Client/Server)架构的开发模式,成为开发企业级应用和电子商务普遍采用的技术。在Web应用开发的早期,主要使用的技术是CGI﹑asp﹑php等。之后,Sun公司推出了基于java语言的Servlet+jsp+JavaBean技术。相比传统的开发技术,它具有跨平台﹑安全﹑有效﹑可移植等特性,这使其更便于使用和开发。

  Java应用程序访问数据库的基本原理

  在Java语言中,JDBC(Java DataBase Connection)是应用程序与数据库沟通的桥梁,

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

  一般来说,Java应用程序访问数据库的过程(如图1所示)是:

  ①装载数据库驱动程序;

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

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

  ④断开数据库连接。

 

  图1 Java数据库访问机制

JDBC作为一种数据库访问技术,具有简单易用的优点。但使用这种模式进行Web应用

  程序开发,存在很多问题:首先,每一次Web请求都要建立一次数据库连接。建立连接是一个费时的活动,每次都得花费0.05s~1s的时间,而且系统还要分配内存资源。这个时间对于一次或几次数据库操作,或许感觉不出系统有多大的开销。可是对于现在的Web应用,尤其是大型电子商务网站,同时有几百人甚至几千人在线是很正常的事。在这种情况下,频繁的进行数据库连接操作势必占用很多的系统资源,网站的响应速度必定下降,严重的甚至会造成服务器的崩溃。不是危言耸听,这就是制约某些电子商务网站发展的技术瓶颈问题。其次,对于每一次数据库连接,使用完后都得断开。否则,如果程序出现异常而未能关闭,将会导致数据库系统中的内存泄漏,最终将不得不重启数据库。还有,这种开发不能控制被创建的连接对象数,系统资源会被毫无顾及的分配出去,如连接过多,也可能导致内存泄漏,服务器崩溃。
  数据库连接池(connection pool)的工作原理
  1、基本概念及原理
由上面的分析可以看出,问题的根源就在于对数据库连接资源的低效管理。我们知道,
  对于共享资源,有一个很著名的设计模式:资源池(Resource Pool)。该模式正是为了解决资源的频繁分配﹑释放所造成的问题。为解决上述问题,可以采用数据库连接池技术。数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。我们可以通过设定连接池最大连接数来防止系统无尽的与数据库连接。更为重要的是我们可以通过连接池的管理机制监视数据库的连接的数量﹑使用情况,为系统开发﹑测试及性能调整提供依据。连接池的基本工作原理见下图2。

图2 连接池的基本工作原理

 2、服务器自带的连接池

  JDBC的API中没有提供连接池的方法。一些大型的WEB应用服务器如BEA的WebLogic和IBM的WebSphere等提供了连接池的机制,但是必须有其第三方的专用类方法支持连接池的用法。
  连接池关键问题分析
  1、并发问题
  为了使连接管理服务具有最大的通用性,必须考虑多线程环境,即并发问题。这个问题相对比较好解决,因为Java语言自身提供了对并发管理的支持,使用synchronized关键字即可确保线程是同步的。使用方法为直接在类方法前面加上synchronized关键字,如:
public synchronized Connection getConnection()
  2、多数据库服务器和多用户
  对于大型的企业级应用,常常需要同时连接不同的数据库(如连接Oracle和Sybase)。如何连接不同的数据库呢?我们采用的策略是:设计一个符合单例模式的连接池管理类,在连接池管理类的唯一实例被创建时读取一个资源文件,其中资源文件中存放着多个数据库的url地址(<poolName.url>)﹑用户名(<poolName.user>)﹑密码(<poolName.passWord>)等信息。如tx.url=192.168.1.123:5000/tx_it,tx.user=cyl,tx.password=123456。根据资源文件提供的信息,创建多个连接池类的实例,每一个实例都是一个特定数据库的连接池。连接池管理类实例为每个连接池实例取一个名字,通过不同的名字来管理不同的连接池。
  对于同一个数据库有多个用户使用不同的名称和密码访问的情况,也可以通过资源文件处理,即在资源文件中设置多个具有相同url地址,但具有不同用户名和密码的数据库连接信息。
  3、事务处理
  我们知道,事务具有原子性,此时要求对数据库的操作符合“ALL-ALL-NOTHING”原则,即对于一组SQL语句要么全做,要么全不做。
在Java语言中,Connection类本身提供了对事务的支持,可以通过设置Connection的AutoCommit属性为false,然后显式的调用commit或rollback方法来实现。但要高效的进行Connection复用,就必须提供相应的事务支持机制。可采用每一个事务独占一个连接来实现,这种方法可以大大降低事务管理的复杂性。
  4、连接池的分配与释放
  连接池的分配与释放,对系统的性能有很大的影响。合理的分配与释放,可以提高连接的复用度,从而降低建立新连接的开销,同时还可以加快用户的访问速度。
  对于连接的管理可使用空闲池。即把已经创建但尚未分配出去的连接按创建时间存放到一个空闲池中。每当用户请求一个连接时,系统首先检查空闲池内有没有空闲连接。如果有就把建立时间最长(通过容器的顺序存放实现)的那个连接分配给他(实际是先做连接是否有效的判断,如果可用就分配给用户,如不可用就把这个连接从空闲池删掉,重新检测空闲池是否还有连接);如果没有则检查当前所开连接池是否达到连接池所允许的最大连接数(maxConn),如果没有达到,就新建一个连接,如果已经达到,就等待一定的时间(timeout)。如果在等待的时间内有连接被释放出来就可以把这个连接分配给等待的用户,如果等待时间超过预定时间timeout,则返回空值(null)。系统对已经分配出去正在使用的连接只做计数,当使用完后再返还给空闲池。对于空闲连接的状态,可开辟专门的线程定时检测,这样会花费一定的系统开销,但可以保证较快的响应速度。也可采取不开辟专门线程,只是在分配前检测的方法。
  5、连接池的配置与维护
  连接池中到底应该放置多少连接,才能使系统的性能最佳?系统可采取设置最小连接数(minConn)和最大连接数(maxConn)来控制连接池中的连接。最小连接数是系统启动时连接池所创建的连接数。如果创建过多,则系统启动就慢,但创建后系统的响应速度会很快;如果创建过少,则系统启动的很快,响应起来却慢。这样,可以在开发时,设置较小的最小连接数,开发起来会快,而在系统实际使用时设置较大的,因为这样对访问客户来说速度会快些。最大连接数是连接池中允许连接的最大数目,具体设置多少,要看系统的访问量,可通过反复测试,找到最佳点。
  如何确保连接池中的最小连接数呢?有动态和静态两种策略。动态即每隔一定时间就对连接池进行检测,如果发现连接数量小于最小连接数,则补充相应数量的新连接,以保证连接池的正常运转。静态是发现空闲连接不够时再去检查。
连接池的实现
  1、连接池模型
  本文讨论的连接池包括一个连接池类(DBConnectionPool)和一个连接池管理类(DBConnetionPoolManager)和一个配置文件操作类(ParseDSConfig)。连接池类是对某一数据库所有连接的“缓冲池”,主要实现以下功能:①从连接池获取或创建可用连接;②使用完毕之后,把连接返还给连接池;③在系统关闭前,断开所有连接并释放连接占用的系统资源;④还能够处理无效连接(原来登记为可用的连接,由于某种原因不再可用,如超时,通讯问题),并能够限制连接池中的连接总数不低于某个预定值和不超过某个预定值。(5)当多数据库时,且数据库是动态增加的话,将会加到配置文件中。
  连接池管理类是连接池类的外覆类(wrapper),符合单例模式,即系统中只能有一个连接池管理类的实例。其主要用于对多个连接池对象的管理,具有以下功能:①装载并注册特定数据库的JDBC驱动程序;②根据属性文件给定的信息,创建连接池对象;③为方便管理多个连接池对象,为每一个连接池对象取一个名字,实现连接池名字与其实例之间的映射;④跟踪客户使用连接情况,以便需要是关闭连接释放资源。连接池管理类的引入主要是为了方便对多个连接池的使用和管理,如系统需要连接不同的数据库,或连接相同的数据库但由于安全性问题,需要不同的用户使用不同的名称和密码。
          2、连接池实现(经过本人改版,可以适用多数据库类型的应用以及一种数据库类型多个数据库且数据   库的数量可以动态增加的应用程序)
          1),DBConnectionPool.java    数据库连接池类
          2),DBConnectionManager .java    数据库管理类
          3),DSConfigBean .java                 单个数据库连接信息Bean
          4),ParseDSConfig.java                 操作多(这个'多'包括不同的数据库和同一种数据库有多个数据库)
                                                             数据 配置文件xml
          5),ds.config.xml                            数据库配置文件xml
          原代码如下:
         DBConnectionPool.java  
         ----------------------------------------------------------
       /**
* 数据库连接池类
*/
package com.chunkyo.db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Timer;
/**
* @author chenyanlin
*
*/
public class DBConnectionPool implements TimerListener {
PRivate Connection con=null;
private int inUsed=0;     //使用的连接数
private ArrayList freeConnections = new ArrayList();//容器,空闲连接
private int minConn;      //最小连接数
private int maxConn;      //最大连接
private String name;      //连接池名字
private String password; //密码
private String url;       //数据库连接地址
private String driver;    //驱动
private String user;      //用户名
public Timer timer;       //定时
/**
   *
   */
public DBConnectionPool() {
   // TODO Auto-generated constructor stub
}
/**
   * 创建连接池
   * @param driver
   * @param name
   * @param URL
   * @param user
   * @param password
   * @param maxConn
   */
public DBConnectionPool(String name, String driver,String URL, String user, String password, int maxConn)
{
   this.name=name;
   this.driver=driver;
   this.url=URL;
   this.user=user;
   this.password=password;
   this.maxConn=maxConn;
}
/**
   * 用完,释放连接
   * @param con
   */
public synchronized void freeConnection(Connection con)
{
   this.freeConnections.add(con);//添加到空闲连接的末尾
   this.inUsed--;
}
/**
   * timeout   根据timeout得到连接
   * @param timeout
   * @return
   */
public synchronized Connection getConnection(long timeout)
{
   Connection con=null;
   if(this.freeConnections.size()>0)
   {
    con=(Connection)this.freeConnections.get(0);
    if(con==null)con=getConnection(timeout); //继续获得连接
   }
   else
   {
    con=newConnection(); //新建连接
   }
   if(this.maxConn==0||this.maxConn<this.inUsed)
   {
    con=null;//达到最大连接数,暂时不能获得连接了。
   }
   if(con!=null)
   {
    this.inUsed++;
   }
   return con;
}
/**
   *
   * 从连接池里得到连接
   * @return
   */
public synchronized Connection getConnection()
{
   Connection con=null;
   if(this.freeConnections.size()>0)
   {
    con=(Connection)this.freeConnections.get(0);
    this.freeConnections.remove(0);//如果连接分配出去了,就从空闲连接里删除
    if(con==null)con=getConnection(); //继续获得连接
   }
   else
   {
    con=newConnection(); //新建连接
   }
   if(this.maxConn==0||this.maxConn<this.inUsed)
   {
    con=null;//等待 超过最大连接时
   }
   if(con!=null)
   {
    this.inUsed++;
    System.out.println("得到 "+this.name+" 的连接,现有"+inUsed+"个连接在使用!");
   }
   return con;
}
/**
   *释放全部连接
   *
   */
public synchronized void release()
{
   Iterator allConns=this.freeConnections.iterator();
   while(allConns.hasNext())
   {
    Connection con=(Connection)allConns.next();
    try
    {
     con.close();
    }
    catch(SQLException e)
    {
     e.printStackTrace();
    }
  
   }
   this.freeConnections.clear();
  
}
/**
   * 创建新连接
   * @return
   */
private Connection newConnection()
{
   try {
    Class.forName(driver);
    con=DriverManager.getConnection(url, user, password);
   } catch (ClassNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    System.out.println("sorry can't find db driver!");
   } catch (SQLException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
    System.out.println("sorry can't create Connection!");
   }
   return con;
 
}
/**
   * 定时处理函数
   */
public synchronized void TimerEvent()
{
      //暂时还没有实现以后会加上的
}
/**
   * @param args
   */
public static void main(String[] args) {
   // TODO Auto-generated method stub
}
/**
   * @return the driver
   */
public String getDriver() {
   return driver;
}
/**
   * @param driver the driver to set
   */
public void setDriver(String driver) {
   this.driver = driver;
}
/**
   * @return the maxConn
   */
public int getMaxConn() {
   return maxConn;
}
/**
   * @param maxConn the maxConn to set
   */
public void setMaxConn(int maxConn) {
   this.maxConn = maxConn;
}
/**
   * @return the minConn
   */
public int getMinConn() {
   return minConn;
}
/**
   * @param minConn the minConn to set
   */
public void setMinConn(int minConn) {
   this.minConn = minConn;
}
/**
   * @return the name
   */
public String getName() {
   return name;
}
/**
   * @param name the name to set
   */
public void setName(String name) {
   this.name = name;
}
/**
   * @return the password
   */
public String getPassword() {
   return password;
}
/**
   * @param password the password to set
   */
public void setPassword(String password) {
   this.password = password;
}
/**
   * @return the url
   */
public String getUrl() {
   return url;
}
/**
   * @param url the url to set
   */
public void setUrl(String url) {
   this.url = url;
}
/**
   * @return the user
   */
public String getUser() {
   return user;
}
/**
   * @param user the user to set
   */
public void setUser(String user) {
   this.user = user;

分享到:
评论

相关推荐

    数据库连接池技术详解

    对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接的配置,实现数据库连接池技术。某一应用最大可用数据库连接数的限制,避免某一应用独占所有数据库资源。 在较为完备的数据库连接池实现中,可根据...

    连接池案例 连接池案例

    连接池案例

    连接池连接池连接池

    连接池连接池连接池连接池连接池

    Http连接池工具类

    传统的HttpURLConnection并不支持连接池,如果要实现连接池的机制,还需要自己来管理连接对象。对于网络请求这种底层相对复杂的操作,个人以为如果有可用的其他方案,也没有必要自己去管理连接对象。 除了...

    Qt 多线程连接数据库——数据库连接池

    * 数据库连接池特点: * 获取连接时不需要了解连接的名字,连接池内部维护连接的名字 * 支持多线程,保证获取到的连接一定是没有被其他线程正在使用 * 按需创建连接,可以创建多个连接,可以控制连接的数量 * 连接...

    SpringBoot2.2+commons-pool2实现多Ftp连接池完整项目,开箱即用,经过长期生产使用稳定可靠

    使用JDK1.8、SpringBoot2.2.10.RELEASE、lombok1.18.8、guava23.0、hutool5.3.10、commons-pool2 2.7.0、tika1.22等实现多Ftp连接池实现,通过守护线程实现连接池内连接可用性校验,配置最大、最小连接个数防止Ftp...

    ADO.NET连接池示例

    ADO.NET链接对象(SqlConnection或者OracleConnection)默认情况都开启连接池(平时编程时可能会忽略)。当我们调用Close或者Dispose方法时,实际并不断开连接,而是把连接放回连接池,再次使用时候重连接池中取得...

    R2数据库连接池高性能连接池v1.3

    v1.3改进了清理线程可能出现的减少连接池中链接而不计数的问题。 v1.2处理了oracle环境下由于服务器关闭休眠链接造成的连接池循环检测进程异常退出的情况,改为当循环周期大于服务器关闭休眠链接间隔时,后台打印...

    ftp连接池实例

    经过几天的琢磨,去看了csdn上一位大牛的数据库的连接池实现方案,从中感悟很多,感谢这位大神。 让我才能有信心去坚持下去。也不知道写的好不好··不好的话,大家指出。但是我是努力去做了,这一个过程,很享受,...

    kafka生产者连接池

    封装抽取了一个kafka生产者的连接池,能很好的用池的方式对kafka生产者连接点进行有效的管理

    C# 数据库连接池 C# 数据库连接池

    C# 数据库连接池 C# 数据库连接池 C# 数据库连接池 C# 数据库连接池

    数据库连接池配置

    这个文档详细讲述了mysql数据库连接池的配置以及数据库连接池的工作原理。

    C#高效数据库连接池源码

    C#高效数据库连接池源码

    Tomcat6配置连接池

    Tomcat6配置连接池很全面的东东

    okhttp中连接池实现

    代码中包含okhhtp中连接池的设计,包含连接对象的添加,连接对象何时被移除。

    连接池管理连接oracle数据库

    这是用连接池技术管理连接oracle数据库的工具类代码,如果想连接MySQL,直接修改配置文件即可。

    RabbitMQ连接池+SpringBoot实现

    RabbitMQ连接池+SpringBoot实现。通过连接池实现将高效的管理RabbitMQ的Connection,并与springboot进行整合,实现消息发送,获取队列列表等功能。基于此可以进行更多功能的扩充。

    java ftp连接池

    在网上找了好久没有现成的ftp连接池jar包,自己花了一些时间实现了一个简单的连接池,用了一段时间稳定性还可以。

    hibernate连接池.doc

    Hibernate支持第三方的连接池,官方推荐的连接池是C3P0,Proxool,以及DBCP 在配置连接池时需要注意的有三点: 一、Apche的DBCP在Hibernate2中受支持,但在Hibernate3中已经不再推荐使用,官方的解释是这个连接池存在...

    java 数据库 连接池驱动.rar

    java 数据库 连接池驱动.rar java 数据库 连接池驱动.rar java 数据库 连接池驱动.rar

Global site tag (gtag.js) - Google Analytics