一、普通的数据库连接
    如下图所示,个用户获取数据库数据都要单独建立一个jdbc连接,当用户获取数据完成后再将连接释放,可见对cpu的资源消耗很大。
JDBC数据库连接池实现原理(手动实现)
JDBC数据库连接池实现原理(手动实现)
 二、建立数据库连接池
    数据库连接池创建后,每次获取数据库数据不需要另外建立连接,而是从连接池里拿出连接进行数据交互
JDBC数据库连接池实现原理(手动实现)
JDBC数据库连接池实现原理(手动实现)
 三、手动实现连接池
核心:使用线程安全的Vector容器装连接Connection(C3P0使用的是LinkedList)
PoolConfig.java数据库连接池属性配置
db.properties配置文件
1
jdbc.driverName = com.mysql.jdbc.Driver
2
jdbc.url = jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncode=true&characterEncoding=utf-8
3
jdbc.userName=root
4
jdbc.password=root
DBUtil.java数据库工具包(数据库开发者调用)
ConnectionPool.java数据库连接池对象(根据配置创建对应连接池)
1
public class ConnectionPool{
2
    private PoolConfig config;//连接池的配置对象
3
    private int count;//记录连接池的连接数
4
    private boolean isActive;//连接池是否被**
5
    //空闲连接集合
6
    private Vector<Connection> freeConn = new Vector<Connection>();
7
    //正在使用的连接集合
8
    private Vector<Connection> userConn = new Vector<Connection>();
9
    //同一个线程无论请求多少次都使用同一个连接(使用ThreadLocal确保)
10
    //每一个线程都私有一个连接
11
    private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();
12
    /*
13
    初始化连接池配置
14
    */
15
    public ConnectionPool(PoolConfig config){
16
        this.config = config;
17
    }
18
    
19
    /*
20
    数据库连接池初始化
21
    */
22
    public void init(){
23
        for(int i=0;i<config.getInitConn();i++){//建立初始连接
24
            //获取连接对象
25
            Connection conn;
26
            try{
27
                conn = getNewConnection();
28
                freeConn.add(conn);
29
                count++;
30
            }catche(SQLException e){
31
                e.printStackTrace();
32
            }
33
            isActive = true;//连接池**
34
        }
35
    }
36
    
37
    /*
38
    获取新数据库连接
39
    */
40
    private synchronized Connection getNewConnection() throws SQLException{
41
        Connection conn = null;
42
        conn = DriverManager.getConnection(config.getUrl(),
43
                                          config.getUserName(),
44
                                          config.getPassword());
45
        return conn;
46
    }
47
    
48
    /*
49
    从连接池获取连接
50
    */
51
    public synchronized Conenction getConnection(){
52
        Connection conn = null;
53
        //当前连接总数小于配置的最大连接数才去获取
54
        if(count<config.getMaxActiveConn()){
55
            //空闲集合中有连接数
56
            if(freeConn.size()>0){
57
                conn = freeConn.get(0);//从空闲集合中取出
58
                freeConn.remove(0);//移除该连接
59
            }else{
60
                conn = getNewConnection();//拿到新连接
61
                count++;
62
            }
63
            if(isEnable(conn)){
64
                useConn.add(conn);//添加到已经使用的连接
65
            }else{
66
                count--;
67
                conn = getConnection();//递归调用到可用的连接
68
            }
69
        }else{//当达到最大连接数,只能阻塞等待
70
            wait(config.getWaitTime());//线程睡眠了一段时间
71
            conn = getConnection();//递归调用
72
        }catch(Exception e){
73
            e.printStackTrace();
74
        }
75
        //将获取的conn设置到本地变量ThreadLocal
76
        threadLocal.set(conn);
77
        return conn;
78
    }
79
    
80
    /*
81
    把用完的连接放回连接池集合Vector中
82
    */
83
    public synchronized void releaseConnection(Connection conn){
84
        if(isEnable(conn)){
85
            if(freeConn.size()<config.getMaxConn()){//空闲连接数没有达到最大
86
                freeConn.add(conn);//放回集合
87
            }else{
88
                conn.close();
89
            }
90
        }
91
        useConn.remove(conn);
92
        count--;
93
        threadLocal.remove();
94
        notifyAll();//放回连接池后说明有连接可用,唤醒阻塞的线程获取连接
95
    }
96
    
97
    /*
98
    获取当前线程的本地变量连接
99
    */
100
    public Connection getCurrentConnection(){
101
        return threadLocal.get();    
102
    }
103
    
104
    /*
105
    判断该连接是否可用
106
    */
107
    private boolean isEnable(Connection conn){
108
        if(conn == null){
109
            return false;
110
        }
111
        if(conn.isClosed()){
112
            return false;
113
        }
114
        return true;
115
    }
116
}

相关文章: