数据库连接池

一、什么是数据库连接池

数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。
 
 

 二、数据源

1、实现数据库连接池

编写连接池需实现java.sql.DataSource接口。DataSource接口中定义了两个重载的getConnection方法:

Connection getConnection()

Connection getConnection(String username, String password)

实现DataSource接口,并实现连接池功能的步骤:

在DataSource构造函数中批量创建与数据库的连接,并把创建的连接加入LinkedList对象中。

实现getConnection方法,让getConnection方法每次调用时,从Linked中取一个Connection返回给用户。

当用户使用完Connection,调用Connection.close()方法时,Collection对象应保证将自己返回到LinkedList中,而不要把conn还给数据库。

  

 1 //实现DataSource接口
 2 public class JdbcPool implements DataSource {
 3     
 4     private static LinkedList<Connection> list = new LinkedList<Connection>();
 5     
 6     //保存配置文件信息
 7     private static Properties config = new Properties();
 8     static{
 9         try {
10             //通过类加载器读取配置文件
11             config.load(JdbcPool.class.getClassLoader().getResourceAsStream("db.properites"));
12             //注册驱动
13             Class.forName(config.getProperty("driver"));
14             
15             
16             //创建10个连接
17             for(int i=0;i<10;i++){
18                 list.add(DriverManager.getConnection(config.getProperty("url"), "username", "password"));
19             }
20         } catch (Exception e) {
21             //抛出初始化异常
22             throw new ExceptionInInitializerError(e);
23         }
24     }
25     
26     
27     @Override
28     //实现连接池注意的问题:
29     //当调用close()方法的时候不是把连接返回给数据库,而是把连接返回给连接池
30     
31     /*
32      * conn.close()
33     /* 在实际开发,发现对象的方法满足不了开发需求时,有三种方式对其进行增强
34      * 1.写一个connecton子类,覆盖close方法,增强close方法
35      * 2.用包装设计模式
36      * 3.用动态代理    aop 面向切面编程
37      */
38     public Connection getConnection() throws SQLException {
39         //如果连接池中没有连接
40         if(list.size()<0){
41             throw new RuntimeException("对不起数据库繁忙");
42             
43         }
44         //从数据库中移除第一个
45         Connection con = list.removeFirst();
46         MyConnection my = new MyConnection(con);
47         return my;
48     }
49     
50     
51     //1.定义一个类,实现与被增强相同的接口
52         //2.在类中定义一个变量,记住被增强对象
53         //3.定义一个构造函数,接收被增强对象
54         //4.覆盖想增强的方法
55         //5.对于不想增强的方法,直接调用目标对象(被增强对象)的方法
56     //增强con对象
57     class MyConnection implements Connection{
58         private Connection conn;
59         public MyConnection(Connection conn){
60             this.conn = conn;
61         }
62         
63         //增强close方法
64         public void close(){
65             list.add(this.conn);
66         }

 

 

2、DBCP数据源

应用程序应在系统中增加如下两个 jar 文件:

Commons-dbcp.jar:连接池的实现

Commons-pool.jar:连接池实现的依赖库

  

配置文件:dbcpconfig.properties
  

#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/day16
username=root
password=root

#<!-- 初始化连接 -->
initialSize=10

#最大连接数量
maxActive=50

#<!-- 最大空闲连接 -->
maxIdle=20

#<!-- 最小空闲连接 -->
minIdle=5

#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=60000


#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;] 
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=utf8

#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true

#driver default 指定由连接池所创建的连接的只读(read-only)状态。
#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
defaultReadOnly=

#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_COMMITTED

 

 

package com.utils;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;

//DBCP连接池
public class JdbcUtils_DBCP {
    //数据库连接池
    private static DataSource ds = null;
    static{
        try{
            //读取配置文件
            InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
            Properties prop = new Properties();
            prop.load(in);
            BasicDataSourceFactory factory = new BasicDataSourceFactory();
            //创建连接池
            ds = factory.createDataSource(prop);
        }catch(Exception e){
            throw new ExceptionInInitializerError(e);
        }
    }
    
    //获取连接的方法
    public static  Connection getConnection() throws SQLException {
        return ds.getConnection();
    }
    
    public static void release(Connection con,Statement st,ResultSet result){
        if(result!=null){
            try{
                result.close();
            }catch(Exception e){
                e.printStackTrace();
            }
            result  = null;
        }
        
        if(st!=null){
            try{
                st.close();
            }catch(Exception e){
                e.printStackTrace();
            }
        }
        
        if(con!=null){
            try {
                con.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

 

 

3、C3P0数据源

配置文件:c3p0-config.xml

<c3p0-config>
  
  <!--默认配置--> <default-config> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/day16</property> <property name="user">root</property> <property name="password">root</property> <property name="initialPoolSize">10</property> <property name="maxIdleTime">30</property> <property name="maxPoolSize">20</property> <property name="minPoolSize">5</property> <property name="maxStatements">200</property> </default-config> <named-config name="mysql"> <property name="acquireIncrement">50</property> <property name="initialPoolSize">100</property> <property name="minPoolSize">50</property> <property name="maxPoolSize">1000</property><!-- intergalactoApp adopts a different approach to configuring statement caching --> <property name="maxStatements">0</property> <property name="maxStatementsPerConnection">5</property> </named-config> <named-config name="oracle"> <property name="acquireIncrement">50</property> <property name="initialPoolSize">100</property> <property name="minPoolSize">50</property> <property name="maxPoolSize">1000</property><!-- intergalactoApp adopts a different approach to configuring statement caching --> <property name="maxStatements">0</property> <property name="maxStatementsPerConnection">5</property> </named-config> </c3p0-config>

 

 

 1 package com.utils;
 2 
 3 import java.sql.Connection;
 4 import java.sql.ResultSet;
 5 import java.sql.SQLException;
 6 import java.sql.Statement;
 7 
 8 import com.mchange.v2.c3p0.ComboPooledDataSource;
 9 
10 public class JdbcUtils_C3P0 {
11     public static ComboPooledDataSource ds = null;
12     
13     static{
14         try{
15             //自动搜索配置文件
16             ds = new ComboPooledDataSource();
17             
18         }catch(Exception e){
19             throw  new ExceptionInInitializerError();
20         }
21     }
22     
23     //获取连接的方法s
24         public static  Connection getConnection() throws SQLException {
25             return ds.getConnection();
26         }
27         
28         //释放连接
29         public static void release(Connection con,Statement st,ResultSet result){
30             if(result!=null){
31                 try{
32                     result.close();
33                 }catch(Exception e){
34                     e.printStackTrace();
35                 }
36                 result  = null;
37             }
38             
39             if(st!=null){
40                 try{
41                     st.close();
42                 }catch(Exception e){
43                     e.printStackTrace();
44                 }
45             }
46             
47             if(con!=null){
48                 try {
49                     con.close();
50                 } catch (Exception e) {
51                     e.printStackTrace();
52                 }
53             }
54         }
55         
56     
57 }    

 

 

4、配置tomcat数据源

在web工程WebRoot/META-INF目录下建立context.xml配置文件如下:

 1 <Context>
 2 
 3     <!-- jdbc/EmployeeDB 为资源的名称 -->
 4      <Resource name="jdbc/EmployeeDB" auth="Container"
 5             type="javax.sql.DataSource"
 6             username="root"
 7             password="root"
 8             driverClassName="com.mysql.jdbc.Driver"
 9             url="jdbc:mysql://localhost:3306/day16"
10             initialSize="10"
11             maxActive="30"
12             maxIdle="4"/>
13 </Context>

 

获取连接池

 1 public class JdbcUtils {
 2     private static DataSource ds;
 3     static {
 4         try {
 5             //初始化JNDI容器
 6             Context initCtx = new InitialContext();
 7             //根据关键字获取容器
 8             Context envCtx = (Context) initCtx.lookup("java:comp/env");
 9             
10             //根据名称获取数据源
11             ds = (DataSource) envCtx.lookup("jdbc/EmployeeDB");
12         } catch (Exception e) {
13             throw new RuntimeException(e);
14         }
15     }
16     
17     //获取连接
18     public static Connection getConnection() throws SQLException{
19         return ds.getConnection();
20     }
21 }

 

注意:

1、mysql的驱动包一定要导进tomcat的lib目录下

2、服务器会自动把META-INF目录下的context.xml加载到conf\Catalina\localhost目录下

 

实现原理:JNDI

JNDI(Java Naming and Directory Interface),Java命名和目录接口,它对应于J2SE中的javax.naming包,

这套API的主要作用在于:它可以把Java对象放在一个容器中(JNDI容器),并为容器中的java对象取一个名称,以后程序想获得Java对象,只需通过名称检索即可。

其核心API为Context,它代表JNDI容器,其lookup方法为检索容器中对应名称的对象。

posted @ 2018-06-12 18:54  牛穿疯  阅读(360)  评论(0编辑  收藏  举报
levels of contents