一個簡易的資料庫連線池
阿新 • • 發佈:2018-12-02
目錄
背景
資料庫連線池是比較寶貴的資源,當有大量的連線時,需要使用資料庫連線池來保證資料庫連線資源的複用。
實現原理
通過一個LinkedList集合來快取連線的例項,通過等待通知機制來實現獲取和釋放連線。等待的時間可設定。
具體實現
資料庫連線池的實現
package com.genersoft; import java.sql.Connection; import java.util.LinkedList; public class ConnectionPool { private LinkedList<Connection> pool = new LinkedList<>(); //初始化資料庫連線池 public ConnectionPool(int initialSize) { for (int i = 0;i < initialSize;i++) { pool.addLast(ConnectionDriver.createConnection()); //System.out.println(""+pool); } } //釋放資料庫連線池 public void releaseConnection(Connection connection) { if (connection != null) { synchronized(pool) { pool.addLast(connection); pool.notifyAll(); } } } //獲取資料庫連線池 public Connection fetchConnection(long mills) throws InterruptedException { synchronized(pool) { if (mills <= 0) { if (pool.isEmpty()) { pool.wait(); } return pool.removeFirst(); } else { long future = System.currentTimeMillis()+mills; long remaining = mills; while (pool.isEmpty() && remaining > 0) { pool.wait(remaining); remaining = future - System.currentTimeMillis(); } Connection result = null; if (!pool.isEmpty()) { result = pool.removeFirst(); } return result; } } } }
Mysql連線的類
package com.genersoft; 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.util.concurrent.TimeUnit; public class ConnectionDriver { public static Connection createConnection() { String url="jdbc:mysql://localhost:3306/test?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&useSSL=false"; String user="root"; String password="root"; Connection conn = null; try { conn = DriverManager.getConnection(url,user,password); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return conn; //return (Connection) Proxy.newProxyInstance(ConnectionDriver.class.getClassLoader(), new Class<?>[] {Connection.class},new Handler() ); } private static class Handler implements InvocationHandler{ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().equals("commit")) { TimeUnit.MILLISECONDS.sleep(100); } return null; } } }
測試類:
package com.genersoft; import java.sql.Connection; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; /** * Hello world! * */ public class ConectionPoolTest { private static CountDownLatch start = new CountDownLatch(1); private static CountDownLatch end; private static ConnectionPool pool = new ConnectionPool(10); public static void main( String[] args ) throws InterruptedException { int threadNum = 30; end = new CountDownLatch(threadNum); int count = 20; AtomicInteger getNum = new AtomicInteger() ; AtomicInteger notGetNum = new AtomicInteger() ; for (int i = 0;i < threadNum;i++) { Thread runnerThread = new Thread(new RunnerThread(count,getNum,notGetNum),"RunnerThread"); runnerThread.start(); } start.countDown(); end.await(); System.out.println("total invoked"+count*threadNum); System.out.println("getNum"+getNum); System.out.println("notGetNum"+notGetNum); } static class RunnerThread implements Runnable{ int count; AtomicInteger getNum ; AtomicInteger notGetNum ; public RunnerThread(int count2,AtomicInteger getNum2,AtomicInteger notGetNum2) { this.count = count2; this.getNum = getNum2; this.notGetNum = notGetNum2; } @Override public void run() { try { start.await(); } catch (InterruptedException e) { e.printStackTrace(); } while (count > 0) { Connection conn; try { conn = pool.fetchConnection(10); if (conn != null) { try { conn.createStatement(); conn.commit(); }finally { pool.releaseConnection(conn); getNum.incrementAndGet(); } }else { notGetNum.incrementAndGet(); } }catch(Exception e) { }finally { count--; } } end.countDown(); } } }
建立一個表格
一個簡單的表格是這麼建立的:
執行緒數量 | 總獲取次數 | 獲取到次數 | 為獲取次數 |
---|---|---|---|
10 | 200 | 200 | 0 |
30 | 600 | 579 | 21 |