當有多個線程,每個線程都需要連接數(shù)據(jù)庫執(zhí)行SQL語句的話,那么每個線程都會創(chuàng)建一個連接,并且在使用完畢后,關(guān)閉連接。
創(chuàng)建連接和關(guān)閉連接的過程也是比較消耗時間的,當多線程并發(fā)的時候,系統(tǒng)就會變得很卡頓。
同時,一個數(shù)據(jù)庫同時支持的連接總數(shù)也是有限的,如果多線程并發(fā)量很大,那么數(shù)據(jù)庫連接的總數(shù)就會被消耗光,后續(xù)線程發(fā)起的數(shù)據(jù)庫連接就會失敗。
原理
與傳統(tǒng)方式不同,連接池在使用之前,就會創(chuàng)建好一定數(shù)量的連接。
如果有任何線程需要使用連接,那么就從連接池里面借用,而不是自己重新創(chuàng)建.
使用完畢后,又把這個連接歸還給連接池供下一次或者其他線程使用。
倘若發(fā)生多線程并發(fā)情況,連接池里的連接被借用光了,那么其他線程就會臨時等待,直到有連接被歸還回來,再繼續(xù)使用。
整個過程,這些連接都不會被關(guān)閉,而是不斷的被循環(huán)使用,從而節(jié)約了啟動和關(guān)閉連接的時間。
package jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class ConnectionPool {
List<Connection> cs = new ArrayList<Connection>();
int size;
public ConnectionPool(int size) {
this.size = size;
init();
}
public void init() {
//這里恰恰不能使用try-with-resource的方式,因為這些連接都需要是"活"的,不要被自動關(guān)閉了
try {
Class.forName("com.mysql.jdbc.Driver");
for (int i = 0; i < size; i++) {
Connection c = DriverManager
.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8", "root", "admin");
cs.add(c);
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public synchronized Connection getConnection() {
while (cs.isEmpty()) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Connection c = cs.remove(0);
return c;
}
public synchronized void returnConnection(Connection c) {
cs.add(c);
this.notifyAll();
}
}
測試
package jdbc;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import jdbc.ConnectionPool;
public class TestConnectionPool {
public static void main(String[] args) {
ConnectionPool cp = new ConnectionPool(3);
for (int i = 0; i < 100; i++) {
new WorkingThread("working thread" + i, cp).start();
}
}
}
class WorkingThread extends Thread {
private ConnectionPool cp;
public WorkingThread(String name, ConnectionPool cp) {
super(name);
this.cp = cp;
}
public void run() {
Connection c = cp.getConnection();
System.out.println(this.getName()+ ":\t 獲取了一根連接,并開始工作" );
try (Statement st = c.createStatement()){
//模擬時耗1秒的數(shù)據(jù)庫SQL語句
Thread.sleep(1000);
st.execute("select * from hero");
} catch (SQLException | InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
cp.returnConnection(c);
}
}