激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - Java實現數據庫連接池簡易教程

Java實現數據庫連接池簡易教程

2020-03-23 12:46PerfectCoder JAVA教程

這篇文章主要為大家介紹了Java實現數據庫連接池簡易教程,感興趣的小伙伴們可以參考一下

一、引言

  池化技術在Java中應用的很廣泛,簡而論之,使用對象池存儲某個實例數受限制的實例,開發者從對象池中獲取實例,使用完之后再換回對象池,從而在一定程度上減少了系統頻繁創建對象銷毀對象的開銷。Java線程池和數據庫連接池就是典型的應用,但并非所有的對象都適合拿來池化,對于創建開銷比較小的對象拿來池化反而會影響性能,因為維護對象池也需要一定的資源開銷,對于創建開銷較大,又頻繁創建使用的對象,采用池化技術會極大提高性能。

  業界有很多成熟的數據庫連接池,比如C3P0,DBCP,Proxool以及阿里的Druid。很多以及開源,在GitHub可以找到源碼,開發者可以根據自己的需求結合各種連接池的特點和性能進行選擇。本文僅是為了了解學習池化技術,實現的一個簡單的數據庫連接池,如有錯誤,還望批評指正。

二、設計

主要類和接口

.ConnectionParam - 數據庫連接池參數類,負責配置數據庫連接以及連接池相關參數。使用Builder實現。

    driver url user password - 連接數據庫所需

    minConnection - 最小連接數

    maxConnection - 最大連接數

    minIdle - 最小空閑連接數

    maxWait - 最長等待時間  

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private final String driver;
 
private final String url;
 
private final String user;
 
private final String password;
 
private final int minConnection;
 
private final int maxConnection;
 
private final int minIdle;
 
private final long maxWait;

.ConnectionPool - 數據庫連接池

    ConnectionPool構造方法聲明為保護,禁止外部創建,交由ConnectionPoolFactory統一管理。

    ConnectionPool實現DataSource接口,重新getConnection()方法。

    ConnectionPool持有兩個容器 - 一個Queue存儲空閑的Connection,另一個Vector(考慮到同步)存儲正在使用的Connection。

    當開發者使用數據庫連接時,從Queue中獲取,沒有則返回空;使用完成close連接時,則放回Vector。

    ConnectionPool提供了一個簡單的基于minIdle和maxConnection的動態擴容機制。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
private static final int INITIAL_SIZE = 5;
 
private static final String CLOSE_METHOD = "close";
 
private static Logger logger;
 
private int size;
 
private ConnectionParam connectionParam;
 
private ArrayBlockingQueue<Connection> idleConnectionQueue;
 
private Vector<Connection> busyConnectionVector;

.ConnectionPoolFactory - 連接池管理類

  ConnectionPoolFactory持有一個靜態ConcurrentHashMap用來存儲連接池對象。

  ConnectionPoolFactory允許創建多個不同配置不同數據庫的連接池。

  開發者首次需要使用特定的名稱注冊(綁定)連接池,以后每次從指定的連接池獲取Connection。

  如果連接池不再使用,開發者可以注銷(解綁)連接池。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private static Map<String, ConnectionPool> poolMap = new ConcurrentHashMap<>();
 
public static Connection getConnection(String poolName) throws SQLException {
 nameCheck(poolName);
 ConnectionPool connectionPool = poolMap.get(poolName);
 return connectionPool.getConnection();
}
 
public static void registerConnectionPool(String name, ConnectionParam connectionParam) {
 registerCheck(name);
 poolMap.put(name, new ConnectionPool(connectionParam));
}
 
// Let GC
public static void unRegisterConnectionPool(String name) {
 nameCheck(name);
 final ConnectionPool connectionPool = poolMap.get(name);
 poolMap.remove(name);
 new Thread(new Runnable() {
  @Override
  public void run() {
   connectionPool.clear();
  }
 }).start();
}

核心代碼

   數據庫連接池核心代碼在于getConnection()方法,通常,開發者處理完數據庫操作后,都會調用close()方法,Connection此時應該被關閉并釋放資源。而在數據庫連接池中,用戶調用close()方法,不應直接關閉Connection,而是要放回池中,重復使用,這里就用到Java動態代理機制,getConnection返回的并不是“真正”的Connection,而是自定義的代理類(此處使用匿名類),當用戶調用close()方法時,進行攔截,放回池中。有關動態代理,可以參看另一篇博客《Java動態代理簡單應用》

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Override
public Connection getConnection() throws SQLException {
 try {
  final Connection connection = idleConnectionQueue.poll(connectionParam.getMaxWait(), TimeUnit.MILLISECONDS);
  if (connection == null) {
   logger.info(emptyMsg());
   ensureCapacity();
   return null;
  }
  busyConnectionVector.add(connection);
  return (Connection) Proxy.newProxyInstance(this.getClass().getClassLoader(),
    new Class[]{Connection.class}, new InvocationHandler() {
     @Override
     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      if (!method.getName().equals(CLOSE_METHOD)) {
       return method.invoke(connection, args);
      } else {
       idleConnectionQueue.offer(connection);
       busyConnectionVector.remove(connection);
       return null;
      }
     }
    });
 } catch (InterruptedException e) {
  e.printStackTrace();
 }
 return null;
}

二、使用

  首先用戶構建數據庫連接池參數(ConnectionParam),包括driver、url、user、password必須項,可以自定義minConnection、maxConnection等可選項,如果不設置,則使用系統默認值,這是使用Builder構建含有大量屬性的好處,其中包括必須屬性和可選屬性。然后向ConnectionPoolFactory使用特定的名稱注冊連接池,最后通過調用ConnectionPoolFactory靜態工廠方法獲取Connection。   

?
1
2
3
4
5
6
7
8
String driver = "com.mysql.jdbc.Driver";
 String url = "jdbc:mysql://localhost:3306/test";
 String user = "root";
 String password = "root";
 
 ConnectionParam connectionParam = new ConnectionParam.ConnectionParamBuilder(driver, url, user, password).build();
 ConnectionPoolFactory.registerConnectionPool("test", connectionParam);
 Connection connection = ConnectionPoolFactory.getConnection("test");

三、代碼

.ParamConfiguration

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package database.config;
 
import java.io.Serializable;
 
/**
 * DataBase Connection Parameters
 * Created by Michael Wong on 2016/1/18.
 */
public class ParamConfiguration implements Serializable {
 
 public static final int MIN_CONNECTION = 5;
 
 public static final int MAX_CONNECTION = 50;
 
 public static final int MIN_IDLE = 5;
 
 public static final long MAX_WAIT = 30000;
 
 private ParamConfiguration() {}
 
}

.Builder

?
1
2
3
4
5
6
7
8
9
10
11
package database;
 
/**
 * Builder
 * Created by Michael Wong on 2016/1/18.
 */
public interface Builder<T> {
 
 T build();
 
}

.ConnectionParam

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package database;
 
import database.config.ParamConfiguration;
 
/**
 * DataBase Connection Parameters
 * Created by Michael Wong on 2016/1/18.
 */
public class ConnectionParam {
 
 private final String driver;
 
 private final String url;
 
 private final String user;
 
 private final String password;
 
 private final int minConnection;
 
 private final int maxConnection;
 
 private final int minIdle;
 
 private final long maxWait;
 
 private ConnectionParam(ConnectionParamBuilder builder) {
  this.driver = builder.driver;
  this.url = builder.url;
  this.user = builder.user;
  this.password = builder.password;
  this.minConnection = builder.minConnection;
  this.maxConnection = builder.maxConnection;
  this.minIdle = builder.minIdle;
  this.maxWait = builder.maxWait;
 }
 
 public String getDriver() {
  return this.driver;
 }
 
 public String getUrl() {
  return this.url;
 }
 
 public String getUser() {
  return this.user;
 }
 
 public String getPassword() {
  return this.password;
 }
 
 public int getMinConnection() {
  return this.minConnection;
 }
 
 public int getMaxConnection() {
  return this.maxConnection;
 }
 
 public int getMinIdle() {
  return this.minIdle;
 }
 
 public long getMaxWait() {
  return this.maxWait;
 }
 
 public static class ConnectionParamBuilder implements Builder<ConnectionParam> {
 
  // Required parameters
  private final String driver;
 
  private final String url;
 
  private final String user;
 
  private final String password;
 
  // Optional parameters - initialized to default value
  private int minConnection = ParamConfiguration.MIN_CONNECTION;
 
  private int maxConnection = ParamConfiguration.MAX_CONNECTION;
 
  private int minIdle = ParamConfiguration.MIN_IDLE;
 
  // Getting Connection wait time
  private long maxWait = ParamConfiguration.MAX_WAIT;
 
  public ConnectionParamBuilder(String driver, String url, String user, String password) {
   this.driver = driver;
   this.url = url;
   this.user = user;
   this.password = password;
  }
 
  public ConnectionParamBuilder minConnection(int minConnection) {
   this.minConnection = minConnection;
   return this;
  }
 
  public ConnectionParamBuilder maxConnection(int maxConnection) {
   this.maxConnection = maxConnection;
   return this;
  }
 
  public ConnectionParamBuilder minIdle(int minIdle) {
   this.minIdle = minIdle;
   return this;
  }
 
  public ConnectionParamBuilder maxWait(int maxWait) {
   this.maxWait = maxWait;
   return this;
  }
 
  @Override
  public ConnectionParam build() {
   return new ConnectionParam(this);
  }
 
 }
 
}

.ConnectionPool

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
package database.factory;
 
import database.ConnectionParam;
 
import javax.sql.DataSource;
import java.io.PrintWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Vector;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
 
/**
 * Connection Pool
 * Created by Michael Wong on 2016/1/18.
 */
public class ConnectionPool implements DataSource {
 
 private static final int INITIAL_SIZE = 5;
 
 private static final String CLOSE_METHOD = "close";
 
 private static Logger logger;
 
 private int size;
 
 private ConnectionParam connectionParam;
 
 private ArrayBlockingQueue<Connection> idleConnectionQueue;
 
 private Vector<Connection> busyConnectionVector;
 
 protected ConnectionPool(ConnectionParam connectionParam) {
  this.connectionParam = connectionParam;
  int maxConnection = connectionParam.getMaxConnection();
  idleConnectionQueue = new ArrayBlockingQueue<>(maxConnection);
  busyConnectionVector = new Vector<>();
  logger = Logger.getLogger(this.getClass().getName());
  initConnection();
 }
 
 private void initConnection() {
  int minConnection = connectionParam.getMinConnection();
  int initialSize = INITIAL_SIZE < minConnection ? minConnection : INITIAL_SIZE;
  try {
   Class.forName(connectionParam.getDriver());
   for (int i = 0; i < initialSize + connectionParam.getMinConnection(); i++) {
    idleConnectionQueue.put(newConnection());
    size++;
   }
  } catch (Exception e) {
   throw new ExceptionInInitializerError(e);
  }
 }
 
 @Override
 public Connection getConnection() throws SQLException {
  try {
   final Connection connection = idleConnectionQueue.poll(connectionParam.getMaxWait(), TimeUnit.MILLISECONDS);
   if (connection == null) {
    logger.info(emptyMsg());
    ensureCapacity();
    return null;
   }
   busyConnectionVector.add(connection);
   return (Connection) Proxy.newProxyInstance(this.getClass().getClassLoader(),
     new Class[]{Connection.class}, new InvocationHandler() {
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       if (!method.getName().equals(CLOSE_METHOD)) {
        return method.invoke(connection, args);
       } else {
        idleConnectionQueue.offer(connection);
        busyConnectionVector.remove(connection);
        return null;
       }
      }
     });
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  return null;
 }
 
 private Connection newConnection() throws SQLException {
  String url = connectionParam.getUrl();
  String user = connectionParam.getUser();
  String password = connectionParam.getPassword();
  return DriverManager.getConnection(url, user, password);
 }
 
 protected int size() {
  return size;
 }
 
 protected int idleConnectionQuantity() {
  return idleConnectionQueue.size();
 }
 
 protected int busyConnectionQuantity() {
  return busyConnectionVector.size();
 }
 
 private void ensureCapacity() throws SQLException {
  int minIdle = connectionParam.getMinIdle();
  int maxConnection = connectionParam.getMaxConnection();
  int newCapacity = size + minIdle;
  newCapacity = newCapacity > maxConnection ? maxConnection : newCapacity;
  int growCount = 0;
  if (size < newCapacity) {
   try {
    for (int i = 0; i < newCapacity - size; i++) {
     idleConnectionQueue.put(newConnection());
     growCount++;
    }
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
  size = size + growCount;
 }
 
 protected void clear() {
  try {
   while (size-- > 0) {
    Connection connection = idleConnectionQueue.take();
    connection.close();
   }
  } catch (InterruptedException | SQLException e) {
   e.printStackTrace();
  }
 }
 
 private String emptyMsg() {
  return "Database is busy, please wait...";
 }
 
 @Override
 public Connection getConnection(String username, String password) throws SQLException {
  return null;
 }
 
 @Override
 public PrintWriter getLogWriter() throws SQLException {
  return null;
 }
 
 @Override
 public void setLogWriter(PrintWriter out) throws SQLException {
 
 }
 
 @Override
 public void setLoginTimeout(int seconds) throws SQLException {
 
 }
 
 @Override
 public int getLoginTimeout() throws SQLException {
  return 0;
 }
 
 @Override
 public Logger getParentLogger() throws SQLFeatureNotSupportedException {
  return null;
 }
 
 @Override
 public <T> T unwrap(Class<T> iface) throws SQLException {
  return null;
 }
 
 @Override
 public boolean isWrapperFor(Class<?> iface) throws SQLException {
  return false;
 }
 
}

 

.ConnectionPoolFactory

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package database.factory;
 
import database.ConnectionParam;
 
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
 
/**
 * Connection Pool Factory
 * Created by Michael Wong on 2016/1/18.
 */
public class ConnectionPoolFactory {
 
 private ConnectionPoolFactory() {}
 
 private static Map<String, ConnectionPool> poolMap = new ConcurrentHashMap<>();
 
 public static Connection getConnection(String poolName) throws SQLException {
  nameCheck(poolName);
  ConnectionPool connectionPool = poolMap.get(poolName);
  return connectionPool.getConnection();
 }
 
 public static void registerConnectionPool(String name, ConnectionParam connectionParam) {
  registerCheck(name);
  poolMap.put(name, new ConnectionPool(connectionParam));
 }
 
 // Let GC
 public static void unRegisterConnectionPool(String name) {
  nameCheck(name);
  final ConnectionPool connectionPool = poolMap.get(name);
  poolMap.remove(name);
  new Thread(new Runnable() {
   @Override
   public void run() {
    connectionPool.clear();
   }
  }).start();
 }
 
 public static int size(String poolName) {
  nameCheck(poolName);
  return poolMap.get(poolName).size();
 }
 
 public static int getIdleConnectionQuantity(String poolName) {
  nameCheck(poolName);
  return poolMap.get(poolName).idleConnectionQuantity();
 }
 
 public static int getBusyConnectionQuantity(String poolName) {
  nameCheck(poolName);
  return poolMap.get(poolName).busyConnectionQuantity();
 }
 
 private static void registerCheck(String name) {
  if (name == null) {
   throw new IllegalArgumentException(nullName());
  }
 }
 
 private static void nameCheck(String name) {
  if (name == null) {
   throw new IllegalArgumentException(nullName());
  }
  if (!poolMap.containsKey(name)) {
   throw new IllegalArgumentException(notExists(name));
  }
 }
 
 private static String nullName() {
  return "Pool name must not be null";
 }
 
 private static String notExists(String name) {
  return "Connection pool named " + name + " does not exists";
 }
 
}

四、測試
JUnit單元測試

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
package database.factory;
 
import database.ConnectionParam;
import org.junit.Test;
 
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
 
import static org.junit.Assert.*;
 
/**
 * ConnectionPoolFactory Test
 * Created by Michael Wong on 2016/1/20.
 */
public class ConnectionPoolFactoryTest {
 
 @Test
 public void testGetConnection() throws SQLException {
 
  String driver = "com.mysql.jdbc.Driver";
  String url = "jdbc:mysql://localhost:3306/test";
  String user = "root";
  String password = "root";
 
  ConnectionParam connectionParam = new ConnectionParam.ConnectionParamBuilder(driver, url, user, password).build();
  ConnectionPoolFactory.registerConnectionPool("test", connectionParam);
 
  List<Connection> connectionList = new ArrayList<>();
 
  for(int i = 0; i < 12; i++) {
   connectionList.add(ConnectionPoolFactory.getConnection("test"));
  }
 
  print();
 
  close(connectionList);
 
  print();
 
  connectionList.clear();
 
  for(int i = 0; i < 12; i++) {
   connectionList.add(ConnectionPoolFactory.getConnection("test"));
  }
 
  print();
 
  close(connectionList);
 
  ConnectionPoolFactory.unRegisterConnectionPool("test");
 
 }
 
 @Test(expected = IllegalArgumentException.class)
 public void testException() {
  try {
   ConnectionPoolFactory.getConnection("test");
  } catch (SQLException e) {
   e.printStackTrace();
  }
 }
 
 private void close(List<Connection> connectionList) throws SQLException {
  for(Connection conn : connectionList) {
   if (conn != null) {
    conn.close();
   }
  }
 }
 
 private void print() {
  System.out.println("idle: " + ConnectionPoolFactory.getIdleConnectionQuantity("test"));
  System.out.println("busy: " + ConnectionPoolFactory.getBusyConnectionQuantity("test"));
  System.out.println("size: " + ConnectionPoolFactory.size("test"));
 }
 
}

以上就是本文的全部內容,希望對大家的學習有所幫助。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 亚洲影视在线观看 | 一级黄色播放 | 国产伦久视频免费观看视频 | 精品久久久久久久久久久aⅴ | 免费a级网站 | 成人黄色小视频在线观看 | 美女网站色免费 | 国产精品久久久久av | 黄网站免费入口 | 黄免费在线观看 | 日本成人在线免费 | 毛片在线视频观看 | 九九热精品在线播放 | 国产一级αv片免费观看 | 成人三级电影在线 | 亚洲爱爱网站 | 久久久久久久久久美女 | 激情小说激情电影 | 亚洲免费资源 | 日日狠狠久久 | 日产精品久久久一区二区福利 | av视在线 | 91精品国产乱码久久久久久久久 | 国产一区二区免费在线观看 | 女教师~淫辱の动漫在线 | 伊人午夜视频 | 国产亚洲精品久久久久久久久 | 粉嫩粉嫩一区二区三区在线播放 | 国产成人精品网站 | 国产超碰人人爽人人做人人爱 | 偿还电影免费看 | 久久久成人免费视频 | 欧美成人午夜精品久久久 | 久久久久亚洲精品 | 欧美日韩国产成人在线观看 | 特黄一区二区三区 | 麻豆视频网 | 黄色电影免费网址 | 久久精品中文字幕一区 | 欧美黄色一级生活片 | 亚洲一区二区中文 |