java數據庫連接池

什麼是數據庫連接池?

數據庫連接的建立是一種耗時、性能低、代價高的操作,頻繁的數據庫連接的建立和關閉極大的影響了系統的性能。數據庫連接池是系統初始化過程中創建一定數量的數據庫連接放於連接池中,當程序需要訪問數據庫時,不再建立一個新的連接,而是從連接池中取出一個已建立的空閒連接,使用完畢後,程序將連接歸還到連接池中,供其他請求使用,從而實現的資源的共享,連接的建立、斷開都由連接池自身來管理。

數據庫連接池爲系統的運行帶來了以下優勢:昂貴的數據庫連接資源得到重用;減少了數據庫連接建立和釋放的時間開銷,提高了系統響應速度;統一的數據庫連接管理,避免了連接資源的泄露。

數據庫連接池創建過程

1. 創建一個ConnectionPool,初始化一定的Connection連接,存放在Vector(線程安全)列表裏。作爲空閒對列。

2. 創建一個AtomicInteger類型的currentActive,作爲記錄活動連接。

3. 創建一個ConnectionPoolEntry對象,封裝Connection和使用初始時間,爲了防止長時間佔用連接。

4. 創建一個ConnectionPoolEntry列表,作爲工作線程。

5. 實現單例

6. 寫一個獲取連接方法。

7. 寫一個回收連接方法。

8. 寫一個監控方法,定時檢查連接是否超時。

源碼

DBPoolEntry類
package dbpool;

import java.sql.Connection;

public class DBPoolEntry {
	private Connection connection;
	
	private long userStartTime;


	public DBPoolEntry(Connection connection, long userStartTime) {
		super();
		this.connection = connection;
		this.userStartTime = userStartTime;
	}


	public Connection getConnection() {
		return connection;
	}


	public long getUserStartTime() {
		return userStartTime;
	}
	
	
}
DBDataSource類
package dbpool;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicInteger;

public class DBDataSource {

	// 當前活躍的連接
	private AtomicInteger currentActive = new AtomicInteger(0);

	// 空閒連接池
	private Vector<Connection> freePools = new Vector<Connection>();

	private DBConfig config;
	// 正在工作的線程
	private Vector<DBPoolEntry> workPools = new Vector<>();

	private final static DBDataSource dataSource = new DBDataSource();

	// 實現單例
	public static DBDataSource getDataSource() {
		return dataSource;
	}

	private DBDataSource() {
		super();
		// TODO Auto-generated constructor stub
		init();
		checkConnection();
	}

	// 初始化連接池
	private void init() {
		// TODO Auto-generated method stub
		config = new DBConfig();

		try {
			// 加載驅動
			Class.forName(config.getDriver());
			// 初始分配空閒連接
			for (int i = 0; i < config.getInitSize(); i++) {
				Connection connection = createConnection();
				freePools.add(connection);
			}

		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	// 創建連接
	private Connection createConnection() {
		// TODO Auto-generated method stub
		Connection connection = null;
		try {
			connection = DriverManager.getConnection(config.getUrl(), config.getUsername(), config.getPassword());
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		currentActive.incrementAndGet(); // 活躍連接加1

		return connection;
	}

	// 獲取連接
	public synchronized Connection getConnection() {
		Connection connection = null;
		if (freePools.size() > 0) {
			connection = freePools.get(0);
			freePools.remove(0);
		} else {
			if (currentActive.get() < config.getMaxSize()) {
				connection = createConnection();
			} else {
				try {
					wait(1000);
					return getConnection();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
				}
			}
		}

		// 得到工作連接初始工作時間,爲了超時
		long userStartTime = System.currentTimeMillis();
		DBPoolEntry dbPoolEntry = new DBPoolEntry(connection, userStartTime);
		workPools.add(dbPoolEntry);
		return connection;

	}

	// 釋放連接
	public synchronized void releaseConnection(Connection connection) {
		try {
			if (!connection.isClosed()) {
				freePools.add(connection);
				for (DBPoolEntry dbPoolEntry : workPools) {
					if (dbPoolEntry.getConnection() == connection) {
						workPools.remove(dbPoolEntry);
						break;
					}
				}
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	// 銷燬連接
	public void checkConnection() {
		new Timer().schedule(new TimerTask() {

			@Override
			public void run() {
				// TODO Auto-generated method stub
				System.out.println("活動數--->"+currentActive);
				System.out.println("空閒對列數--->" + freePools.size());
				System.out.println("工作隊列數--->" + workPools.size());
				System.out.println();
				for (DBPoolEntry dbPoolEntry : workPools) {
					long userStartTime = dbPoolEntry.getUserStartTime();
					long currentTime = System.currentTimeMillis();
					if (currentTime - userStartTime >= config.getTimeout()) {
						try {
							// 連接超時,關閉連接
							dbPoolEntry.getConnection().close();
							// 從工作對列裏面刪除
							workPools.remove(dbPoolEntry);
							// 活躍連接減1
							currentActive.decrementAndGet();
							break;
						} catch (SQLException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				}

			}
		}, 50L, 1000L);
	}

}


測試類
package dbpool;

import java.sql.Connection;
import java.util.Random;

public class DBConnectionPool {
	/*
	 * 數據源
	 */
	private static DBDataSource dbDataSource = DBDataSource.getDataSource();

	public static Connection getConnection() {
		return dbDataSource.getConnection();
	}

	public static void close(Connection connection) {
		dbDataSource.releaseConnection(connection);
	}

	public static void main(String[] args) {
		MyThread myThread = new MyThread();

		for (int j = 0; j < 1; j++) {

			for (int i = 0; i < 60; i++) {
				new Thread(myThread).start();
			}
			System.out.println("*----------*");
		}

	}

}

class MyThread implements Runnable {

	@Override
	public void run() {
		// TODO Auto-generated method stub
		Connection connection = DBConnectionPool.getConnection();
		try {
			//模擬工作
			Random random = new Random();
			int i = random.nextInt(10);

			Thread.sleep(i * 300);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		DBConnectionPool.close(connection);
	}

}

測試結果
*----------*
活動數--->9
空閒對列數--->0
工作隊列數--->9

活動數--->10
空閒對列數--->5
工作隊列數--->5

活動數--->10
空閒對列數--->3
工作隊列數--->7

活動數--->10
空閒對列數--->5
工作隊列數--->5

活動數--->10
空閒對列數--->7
工作隊列數--->3

活動數--->10
空閒對列數--->5
工作隊列數--->5

活動數--->10
空閒對列數--->4
工作隊列數--->6

活動數--->10
空閒對列數--->4
工作隊列數--->6

活動數--->10
空閒對列數--->4
工作隊列數--->6

活動數--->9
空閒對列數--->3
工作隊列數--->6

活動數--->8
空閒對列數--->6
工作隊列數--->2

活動數--->7
空閒對列數--->7
工作隊列數--->0

活動數--->7
空閒對列數--->7
工作隊列數--->0


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章