国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

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

香港云服务器
服務(wù)器之家 - 編程語言 - JAVA教程 - Java實現(xiàn)數(shù)據(jù)庫連接池簡易教程

Java實現(xiàn)數(shù)據(jù)庫連接池簡易教程

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

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

一、引言

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

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

二、設(shè)計

主要類和接口

.ConnectionParam - 數(shù)據(jù)庫連接池參數(shù)類,負(fù)責(zé)配置數(shù)據(jù)庫連接以及連接池相關(guān)參數(shù)。使用Builder實現(xiàn)。

    driver url user password - 連接數(shù)據(jù)庫所需

    minConnection - 最小連接數(shù)

    maxConnection - 最大連接數(shù)

    minIdle - 最小空閑連接數(shù)

    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 - 數(shù)據(jù)庫連接池

    ConnectionPool構(gòu)造方法聲明為保護(hù),禁止外部創(chuàng)建,交由ConnectionPoolFactory統(tǒng)一管理。

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

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

    當(dāng)開發(fā)者使用數(shù)據(jù)庫連接時,從Queue中獲取,沒有則返回空;使用完成close連接時,則放回Vector。

    ConnectionPool提供了一個簡單的基于minIdle和maxConnection的動態(tài)擴(kuò)容機(jī)制。

?
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持有一個靜態(tài)ConcurrentHashMap用來存儲連接池對象。

  ConnectionPoolFactory允許創(chuàng)建多個不同配置不同數(shù)據(jù)庫的連接池。

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

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

?
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();
}

核心代碼

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

?
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;
}

二、使用

  首先用戶構(gòu)建數(shù)據(jù)庫連接池參數(shù)(ConnectionParam),包括driver、url、user、password必須項,可以自定義minConnection、maxConnection等可選項,如果不設(shè)置,則使用系統(tǒng)默認(rèn)值,這是使用Builder構(gòu)建含有大量屬性的好處,其中包括必須屬性和可選屬性。然后向ConnectionPoolFactory使用特定的名稱注冊連接池,最后通過調(diào)用ConnectionPoolFactory靜態(tài)工廠方法獲取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"));
 }
 
}

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助。

延伸 · 閱讀

精彩推薦
386
主站蜘蛛池模板: 免费看黄在线网站 | 日本在线免费观看 | 国产亚洲欧美一区 | 日本a v在线播放 | 日本一区二区不卡 | 欧美精品入口蜜桃 | 亚洲第一av网站 | 精品无码久久久久久久动漫 | 日本亚洲欧美 | 亚洲一区中文字幕在线观看 | 欧美欧美欧美 | 久久九九| 欧美亚洲视频在线观看 | 欧美日韩免费一区二区三区 | 色678黄网站全部免费 | 国产98色在线 | 日韩 | 成人在线视频网站 | 久久精品无码一区二区三区 | 精品国产黄a∨片高清在线 久草.com | 一级片在线播放 | 精品成人一区二区三区 | 波多野结衣一区二区三区免费视频 | 国产精品污www一区二区三区 | 午夜精品一区二区三区在线播放 | 久久丁香 | 国产一区二区三区 | 伊人在线| 91国产精品| 在线黄色网 | 欧美视频日韩视频 | 国产精品久久久久久一区二区三区 | 一级黄色大片免费 | 久久久久久久av | 黄色片免费观看网站 | 天堂中文网 | 久久久精品综合 | 欧美二区三区 | 色在线影院 | 欧美一区二区三区在线观看视频 | 午夜精 | 久久女人网 |