数据库连接池的原理与实现(详解)

 数据库连接池(功能说明)

1、基本概念及原理

A.对于共享资源,有一个很著名的设计模式:资源池 (Resource Pool)。该模式正是为了解决资源的频繁分配?释放所造成的问题。

B.为解决上述问题,可以采用数据库连接池技术。数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。

C.预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。

D.我们可以通过设定 连接池最大连接数来防止系统无尽的与数据库连接。更为重要的是我们可以通过连接池的管理机制监视数据库的连接的数量使用情况,为系统开发,测试及性能调整提供依据

 

2.多数据库服务器和多用户

对于很多企业来说,可能要访问不同的数据库,例如Oracle与SqlServer如何连接不同的数据库?

采取措施:

A.设计一个符合单例模式的连接池管理类.

B.在连接池管理类唯一实例被创建的时候去读取一个资源文件,资源文件里面记录了相应的数据库信息,例如url,user,password等信息.

C.创建多个连接池的实例,每一个实例都是一个特定数据库的连接池,连接池管理类实例,为每个连接池取一个名字,通过不同的名字来管理不同的连接池.

D.对于同一个数据库有多个用户使用不同的名称和密码访问的情况,也可以通过资源文件去处理,即使用同一个url使用不同的用户名和密码的数据库连接信息

3.事物处理

默认情况下,java.sql.Connection对象处于自动提交模式下,意味着它执行每句语句都会自动提交更改.

有时我们需要保持一些事物的原子性,即要么同时成功要么同时回滚.

例如,用户买了一本书,则需要把书的库存减去1.同时,需要将该客户的购物车订单增加1.它们需要同时成功

A调用conncetion.setAutoCommit(false)

B执行相应的一系列数据操作

c,提交connection.commit();

4.连接池的分配与释放

1.空闲连接池(存放已经创建但并未分配出去的连接,按照创建时间大小放在一个容器)

2.用户请求连接时会看连接池内是否还有空闲连接..分配一个最大创建时间的连接给它

3.如果有空闲连接.判断该连接是否有效,如果是无效的连接,则把它移出连接池,重新检测是否还有其他空闲的连接

4.如果没有剩余空闲的连接,检查当前所开的连接池数是否达到连接池所允许的最大数,如果没有达到就分配一个新的连接,如果达到了就等待一段时间。

5.在等待的时间内,任何连接被释放出来后都可以把这个连接分配给等待的客户

6.如果等待时间超过预定的时间则返回null值,系统对已经分配出去了的正在使用的连接只做计数

 

5.连接池的配置与维护

A.设置最小连接数和最大连接数,如果设置过多,系统启动就慢,访问速度快。设置过少的话则启动快访问的时候慢.

B.开发的时候设置较小的最小连接数,这样保证开发起来较快.系统实际使用时,设置较大的连接数保证访问速度.

C.最大连接数具体值要看系统的访问量.要经过不断测试取一个平衡值

D.隔一段时间对连接池进行检测,发现小于最小连接数的则补充相应数量的新连接

----------------------------------------------------------------------------------

数据库连接池类的设计
类1:数据库连接池类DBconnctionPool
属性:
inuserd 当前正在使用的连接数(int 类型)
maxConn 最大的连接数(int 类型)
minConn 最小的连接数(int 类型)
poolName 连接池的名称(String 类型)
ArrayList freeConnections=new ArrayList() (容器,用来装空闲的连接)
username 用户名(String类型)
password 密码(String 类型)
url 连接的地址(String 类型)
driver 驱动(String类型)
方法:
1.构造方法
//构造器函数
public DBconnctionPool(int maxConn, String username, String password,
        String url, String driver) {
    super();
    this.maxConn = maxConn;
    this.username = username;
    this.password = password;
    this.url = url;
    this.driver = driver;
}
2.用完释放连接的方法
public synchronized void freeConnection(Connection conn){
    freeConnections.add(conn);
    inuserd--;
}
3.创建新连接的方法
public Connection createConnection() {
    Connection conn = null;
    try {
        Class.forName(driver);
        conn = DriverManager.getConnection(url, username, password);
    } catch (ClassNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        System.out.println("sorry,can‘t find the driver");
    } catch (SQLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        System.out.println("can‘t connect...");
    }
    return conn;
}
4.从连接池得到连接的方法
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;
 }
 5.释放所有空闲连接的方法
 public synchronized void release(){
    Iterator allconns=freeConnections.iterator();
    while(allconns.hasNext()){
        Connection conn=(Connection) allconns.next();
        try {
            conn.close();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    //移除集合里的所有元素
    freeConnections.clear();
}

类2:数据库连接池管理类
package com.crm.util.pool;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

/**
 * 数据库连接池管理类
 * @author abcd
 *
 */
public class DBconnectionManager {
    public int clients;//客户的连接数
    static private DBconnectionManager instance;//唯一的连接池管理类实例
    HashMap<String,DBconnctionPool> connectPools=new HashMap<String,DBconnctionPool>();
    
    ArrayList<DsconfigBean> drivers=new ArrayList<DsconfigBean>();//bean类集合
    
    /**
     * 利用单例模式保证取得唯一的连接池管理类实例
     * @return
     */
    static public DBconnectionManager getInstance(){
        if(instance==null){
            instance=new DBconnectionManager();
        }
        return instance;
    }
    /**
     * 创建连接池
     * @param bean
     */
    public void createPool(DsconfigBean bean){
        
        DBconnctionPool pool=new DBconnctionPool();
        System.out.println(bean.getName());
        pool.setDriver(bean.getDriver());
        pool.setMaxConn(bean.getMaxCount());
        pool.setPassword(bean.getPassword());
        pool.setPoolName(bean.getName());
        pool.setUrl(bean.getUrl());
        pool.setUsername(bean.getUsername());
        connectPools.put(bean.getName(), pool);
    }
    /**
     * 加载驱动程序
     */
    public void loadDrivers(){
        ParseConfig oaConfig=new ParseConfig();
        drivers=oaConfig.ReadConfig();
        
    }
    /**
     * 初始化连接池参数
     * 1.调用类读取配置文件
     * 2.把读取到的有关driver的信息存储在集合drivers里
     */
    public void init(){
        loadDrivers();
        //遍历迭代创建相应的连接池
        DsconfigBean myBean=new DsconfigBean();
        
        for(int i=0;i<drivers.size();i++){
            myBean=drivers.get(i);
            createPool(myBean);
        }
        
    }
    /**
     * 根据连接池的名字得到一个连接
     * @param name
     * @return
     */
    public Connection getConnection(String name){
        DBconnctionPool pool=null;
        Connection conn=null;
        
        pool=(DBconnctionPool)connectPools.get(name);
        conn=pool.getConnection();
        return conn;
    }
    
    
}

类3:配置文件对应的bean类
package com.crm.util.pool;
/**
 * 配置文件Bean类
 * @author abcd
 *
 */
public class DsconfigBean {
    private String name;//数据库名字
    private String type;//连接池类型
    private String driver;//连接池驱动
    private String url;//连接池地址
    private String username;//用户名
    private String password;//密码
    private int maxCount;//最大连接数
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    public String getDriver() {
        return driver;
    }
    public void setDriver(String driver) {
        this.driver = driver;
    }
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public int getMaxCount() {
        return maxCount;
    }
    public void setMaxCount(int maxCount) {
        this.maxCount = maxCount;
    }
    
}

类4:解析添加配置文件的类
package com.crm.util.pool;

import java.util.ArrayList;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * 操作配置文件的类
 * @author abcd
 *
 */
public class ParseConfig {
    /**
     * 利用dom4j包读取配置文件内容返回集合beans
     * @return
     */
    public  ArrayList<DsconfigBean> ReadConfig(){
        ArrayList<DsconfigBean> beans=new ArrayList<DsconfigBean>();
        //得到解析器
        SAXReader saxReader=new SAXReader();
        //设置ErrorHander
        saxReader.setErrorHandler(new DefaultHandler(){
            public void error(SAXParseException ex){
                System.out.println(ex.getSystemId()+"文档的第"+ex.getLineNumber()+"行,第"+
                        ex.getColumnNumber()+"列"+"发生错误"+ex.getMessage());
            }
        });
        //创建树形结构开始解析
        try {
            Document document=saxReader.read("dsconfig.xml");
            Element root=document.getRootElement();//得到根节点
            //获得所有的pool下的节点
            List<Node> nodes=document.selectNodes("ds-config/pool");
            //System.out.println(nodes.size());
            //遍历节点
            for (Node node : nodes) {
                DsconfigBean dsconfigBean=new DsconfigBean();
                Node node1=node.selectSingleNode("driver");
                Node node2=node.selectSingleNode("username");
                Node node3=node.selectSingleNode("password");
                Node node4=node.selectSingleNode("url");
                Node node5=node.selectSingleNode("maxconn");
                Node node6=node.selectSingleNode("type");
                dsconfigBean.setDriver(node1.getStringValue());
                dsconfigBean.setUsername(node2.getStringValue());
                dsconfigBean.setPassword(node3.getStringValue());
                dsconfigBean.setUrl(node4.getStringValue());
                dsconfigBean.setMaxCount(Integer.valueOf(node5.getStringValue()));
                dsconfigBean.setName(node6.getStringValue());
                beans.add(dsconfigBean);
    
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return beans;
        
    }
}
5.配置文件dsconfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<ds-config>
<pool>
<type>mysql</type>
<name>user</name>
<driver>com.mysql.jdbc.driver</driver>
<url>jdbc:mysql://localhost:3306/user</url>
<username>sa</username>
<password>123456</password>
<maxconn>100</maxconn>
</pool>

<pool>
<type>mysql</type>
<name>user2</name>
<driver>com.mysql.jdbc.driver</driver>
<url>jdbc:mysql://localhost:3306/user2</url>
<username>sa</username>
<password>1234</password>
<maxconn>10</maxconn>
</pool>
<pool>
<type>sqlserver</type>
<name>books</name>
<driver>com.microsoft.sqlserver.jdbc.SQLServerDriver</driver>
<url>jdbc:sqlserver://localhost:1433;DatabaseName=GZLCRM</url>
<username>sa</username>
<password>123</password>
<maxconn>100</maxconn>
</pool>
</ds-config>
6.测试类DBTest
package com.crm.util.pool;

import java.sql.Connection;

/**
 * 测试连接池的类
 * @author abcd
 *
 */
public class DBTest {
    public static void main(String[] args) {
        DBconnectionManager manager=DBconnectionManager.getInstance();
        manager.init();
        Connection connection=manager.getConnection("sqlserver");
        System.out.println(connection.toString());
    }
}



数据库连接池的原理与实现(详解),古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。