數據庫連接池的使用
傳統方式
當有多個線程,每個線程都需要連接數據庫執行SQL語句的話,那麼每個線程都會創建一個連接,並且在使用完畢後,關閉連接。這一點自己在平時寫程序的時候都是自己創建connection對象,然後用完就關閉。這就很耗時和浪費資源
創建連接和關閉連接的過程也是比較消耗時間的,當多線程併發的時候,系統就會變得很卡頓。
同時,一個數據庫同時支持的連接總數也是有限的,如果多線程併發量很大,那麼數據庫連接的總數就會被消耗光,後續線程發起的數據庫連接就會失敗。
改進方式:
與傳統方式不同,連接池在使用之前,就會創建好一定數量的連接。
如果有任何線程需要使用連接,那麼就從連接池裏面借用,而不是自己重新創建.
使用完畢後,又把這個連接歸還給連接池供下一次或者其他線程使用。
倘若發生多線程併發情況,連接池裏的連接被借用光了,那麼其他線程就會臨時等待,直到有連接被歸還回來,再繼續使用。
整個過程,這些連接都不會被關閉,而是不斷的被循環使用,從而節約了啓動和關閉連接的時間。
還記得上安卓課時候,張吳波老師說連接池就像一個魚缸一樣,要吃魚的時候就拿出一條來,吃完了就放回去,把我們都逗笑了。。。。23333
代碼
自定義數據庫連接池的實現代碼:就是借用操作系統中的生產者-消費者模型,來維護一個緩衝區。這次進行併發控制。
package dbpool;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.LinkedList;
/**
* describe:
*
* @author yanzhizheng
* @date 2019//26
* 按照how2j上實現的線程池
*/
public class ConnectPool {
private LinkedList<Connection> pool = new LinkedList<Connection>();
int size;
public ConnectPool(int size) {
this.size = size;
init(); //調用init方法初始化隊列
}
public void init(){
//加載驅動源
try {
Class.forName("com.mysql.jdbc.Driver");
for (int i = 0; i < size; i++) {
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test",
"root","mysql");
pool.addLast(conn);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
}
}
public synchronized Connection getConnection(){
while (pool.isEmpty()) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return pool.removeFirst();
}
public synchronized void releaseConnction(Connection conn) {
pool.addLast(conn);
this.notifyAll(); //喚醒等待的進程
}
public static void main(String[] args) {
ConnectPool pool = new ConnectPool(3); //初始化10個連接對象放到池子中
for (int i = 0; i < 10; i++) {
new WorkThread("work thread" + i, pool).start();
}
}
}
class WorkThread extends Thread {
private ConnectPool pool;
public WorkThread(String name, ConnectPool pool) {
super(name);
this.pool = pool;
}
public void run() {
Connection c = pool.getConnection();//獲取連接池中的連接
System.out.println(this.getName() + ":\t 獲取連接" + "連接的對象的值" + c.toString());
try(Statement psmt = c.createStatement()) {
Thread.sleep(10000); //睡眠10ms容易有效果
//執行sql語句
} catch (SQLException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
pool.releaseConnction(c);
}
}
代碼結果
可以看到後面的線程都是使用那三個連接對象。