1、簡介
數據庫連接池負責分配、管理和釋放數據庫連接,它允許應用程序重復使用一個現有的數據庫連接,而不是再重新建立一個;釋放空閑時間超過最大空閑時間的數據庫連接來避免因為沒有釋放數據庫連接而引起的數據庫連接遺漏。這項技術能明顯提高對數據庫操作的性能。
2、為什么要用連接池
如果按照單個連接來進行數據庫操作,在高並發的情況下會導致數據庫連接數耗盡的問題,而且單個連接的頻繁創建和關閉,極大地增加了數據庫的開銷。針對這些,數據庫連接池技術就能很好的解決這些問題。
3、實現
定義連接對象

import java.sql.Connection; /** * */ public class PoolConnection { private Connection connect; //false 繁忙,true 空閑 private boolean status; public PoolConnection() { } public PoolConnection(Connection connect, boolean status) { this.connect = connect; this.status = status; } public Connection getConnect() { return connect; } public void setConnect(Connection connect) { this.connect = connect; } public boolean isStatus() { return status; } public void setStatus(boolean status) { this.status = status; } //釋放連接池中的連接對象 public void releaseConnect(){ this.status = true; } }
定義一個接口獲取連接對象
public interface DataSource { PoolConnection getDataSource(); }
實現類

public class DataSourceImpl implements DataSource { private ReentrantLock lock = new ReentrantLock(); //定義連接池中連接對象的存儲容器 private List<PoolConnection> list = Collections.synchronizedList(new LinkedList<>()); //定義數據庫連接屬性 private final static String DRIVER_CLASS = PropertiesUtils.getInstance().getProperty("jdbc.driver_class"); private final static String URL = PropertiesUtils.getInstance().getProperty("jdbc.url"); private final static String USERNAME = PropertiesUtils.getInstance().getProperty("jdbc.username"); private final static String PASSWORD = PropertiesUtils.getInstance().getProperty("jdbc.password"); //定義默認連接池屬性配置 private int initSize = 2; private int maxSize = 4; private int stepSize = 1; private int timeout = 2000; public DataSourceImpl() { initPool(); } //初始化連接池 private void initPool() { String init = PropertiesUtils.getInstance().getProperty("initSize"); String step = PropertiesUtils.getInstance().getProperty("stepSize"); String max = PropertiesUtils.getInstance().getProperty("maxSize"); String time = PropertiesUtils.getInstance().getProperty("timeout"); initSize = init == null ? initSize : Integer.parseInt(init); maxSize = max == null ? maxSize : Integer.parseInt(max); stepSize = step == null ? stepSize : Integer.parseInt(step); timeout = time == null ? timeout : Integer.parseInt(time); try { //加載驅動 Driver driver = (Driver) Class.forName(DRIVER_CLASS).newInstance(); //使用DriverManager注冊驅動 DriverManager.registerDriver(driver); } catch (Exception e) { e.printStackTrace(); } } @Override public PoolConnection getDataSource() { PoolConnection poolConnection = null; try { lock.lock(); //連接池對象為空時,初始化連接對象 if (list.size() == 0) { createConnection(initSize); } //獲取可用連接對象 poolConnection = getAvailableConnection(); //沒有可用連接對象時,等待連接對象的釋放或者創建新的連接對象使用 while (poolConnection == null) { System.out.println("---------------等待連接---------------"); createConnection(stepSize); poolConnection = getAvailableConnection(); if (poolConnection == null) { TimeUnit.MILLISECONDS.sleep(30); } } } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } return poolConnection; } //創建數據庫連接 private void createConnection(int count) throws SQLException { if (list.size() + count <= maxSize) { for (int i = 0; i < count; i++) { System.out.println("初始化了" + (i + 1) + "個連接"); Connection connect = DriverManager.getConnection(URL, USERNAME, PASSWORD); PoolConnection pool = new PoolConnection(connect, true); list.add(pool); } } } // 獲取可用連接對象 private PoolConnection getAvailableConnection() throws SQLException { for (PoolConnection pool : list) { if (pool.isStatus()) { Connection con = pool.getConnect(); // 驗證連接是否超時 if (!con.isValid(timeout)) { Connection connect = DriverManager.getConnection(URL, USERNAME, PASSWORD); pool.setConnect(connect); } pool.setStatus(false); return pool; } } return null; } }
相關的PropertiesUtils 工具類

public class PropertiesUtils extends Properties { private static final long serialVersionUID = 1L; //定義屬性文件名稱 private final static String PROPERTY_FILE = "datasource.properties"; private static PropertiesUtils propertiesHolder = null; private PropertiesUtils() { if (propertiesHolder != null) { throw new RuntimeException("此類是單例,已經存在實例化對象了。"); } } public static PropertiesUtils getInstance() { if (propertiesHolder == null) { synchronized (PropertiesUtils.class) { if (propertiesHolder == null) { propertiesHolder = new PropertiesUtils(); try (InputStream input = propertiesHolder.getClass().getClassLoader().getResourceAsStream(PROPERTY_FILE)) { propertiesHolder.load(input); } catch (Exception e) { e.printStackTrace(); } } } } return propertiesHolder; } }
4、測試類

public class PoolTest { public static void main( String[] args ) { DataSource source = new DataSourceImpl(); CountDownLatch latch = new CountDownLatch(3); int i = 0; for(; i < 3; i++){ new Thread(new Runnable() { @Override public void run() { PreparedStatement pre = null; ResultSet result = null; try { PoolConnection connect = source.getDataSource(); String sql = "select * from LEVEL4 where LEVEL4_CODE like ?"; pre = connect.getConnect().prepareCall(sql); pre.setString(1, "%3AL34812ABAA%"); // 執行查詢,注意括號中不需要再加參數 result = pre.executeQuery(); while (result.next()) { // 當結果集不為空時 System.out.println("LEVEL4_CODE: " + result.getString("LEVEL4_CODE")); } TimeUnit.SECONDS.sleep(1); connect.releaseConnect(); latch.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } }).start(); } try { latch.await(); System.out.println("-------結束-----------"); } catch (InterruptedException e) { e.printStackTrace(); } } }