Java operation of the database - manually implement database connection pool
Abstract: This paper to learn how to manually implement a database connection pool, as well as some improvements on this basis.
Part of the contents from the following blog:
https://blog.csdn.net/soonfly/article/details/72731144
A simple database connection pool
Connection pooling tools
Queue storage resources are connected using a connection pool thread-safe, to ensure the security thread.
It provides a method to get a connection and release of the connection, connection to achieve the recycling of resources.
When thread technology, the use of atomic class, to ensure that the thread count in a multithreaded environment safety.
code show as below:
. 1 public class DataPoolUtils { 2 // active connections, a thread-safe queue . 3 Private static a LinkedBlockingQueue <Connection> = BUSY new new a LinkedBlockingQueue <Connection> (); . 4 // idle connection, a thread-safe queue . 5 Private static a LinkedBlockingQueue <Connection > IDLE = new new a LinkedBlockingQueue <connection> (); . 6 // created connections, using class implements thread-safe atomic operation . 7 Private static of AtomicInteger createCount = new new of AtomicInteger (0 ); . 8 // maximum number of connections 9 private static int maxConnection = 5; 10 // 最大等待毫秒数 11 private static int maxWaitTimeout = 1000; 12 13 /** 14 * 创建连接 15 * @return 16 * @throws Exception 17 */ 18 private Connection createConnection() throws Exception { 19 Properties pros = new Properties(); 20 InputStream is = DataPoolUtils.class.getClassLoader().getResourceAsStream("jdbc.properties"); 21 pros.load(is); 22 String driverClass = pros.getProperty("driverClass"); 23 Class.forName(driverClass); 24 String url = pros.getProperty("url"); 25 String user = pros.getProperty("user"); 26 String password = pros.getProperty("password"); 27 return DriverManager.getConnection(url, user, password); 28 } 29 30 /** 31 * 关闭连接 32 * @param connection 33 */ 34 private void closeConnection(Connection connection) { 35 try { 36 if (!connection.isClosed()) { 37 connection.close(); 38 } 39 } catch (SQLException e) { 40 e.printStackTrace(); 41 } 42 } 43 44 /** 45 * 获取连接 46 * @return 47 * @throwsException 48 * / 49 public Connection the getConnection () throws Exception { 50 // try to obtain idle connection 51 is Connection Connection = idle.poll (); 52 is IF (Connection == null ) { 53 is // attempt to create a connection, using a double check CAS is smaller than the maximum number of connections existing connections 54 is iF (createCount.get () < maxConnection) { 55 iF (createCount.incrementAndGet () <= maxConnection) { 56 is connection = the createConnection (); 57 is } the else{ 58 createCount.decrementAndGet (); 59 } 60 } 61 is // try to acquire an idle connection wait, wait for time-out mechanism to achieve 62 is IF (Connection == null ) { 63 is Connection = idle.poll (maxWaitTimeout, TimeUnit.MILLISECONDS); 64 IF (connection == null ) { 65 the throw new new Exception ( "Get connection timeout" ); 66 } 67 } 68 } 69 busy.offer (connection); 70 return Connection; 71 is } 72 73 is / ** 74 * return connection 75 * @param Connection 76 * / 77 public void the releaseConnection (Connection Connection) { 78 // process air connection 79 IF (Connection == null ) { 80 createCount. decrementAndGet (); 81 return ; 82 } 83 // process removes failed connection 84 Boolean removeResult = busy.remove(connection); 85 if (!removeResult) { 86 closeConnection(connection); 87 createCount.decrementAndGet(); 88 return; 89 } 90 // 处理已经关闭的连接 91 try { 92 if (connection.isClosed()) { 93 createCount.decrementAndGet(); 94 return; 95 } 96 } catch (SQLException e) { 97 e.printStackTrace(); 98 } 99 // process connection failure added 100 Boolean offerResult = idle.offer (Connection); 101 IF (! OfferResult) { 102 closeConnection (Connection); 103 createCount.decrementAndGet (); 104 return ; 105 } 106 } 107 }
Test the connection pool of business class
In order to achieve the recycling of threads, thread pool needs to call the release method of connection resources, rather than directly off the connection resources.
code show as below:
. 1 public class TestPool { 2 // create a configuration file name of the connection pool . 3 Private static DataPoolUtils the pool = new new DataPoolUtils ( ); . 4 . 5 / ** . 6 * main routine . 7 * / . 8 public static void main (String [] args ) { 9 // simulate multiple query the database 10 for ( int I = 0; I <. 6; I ++ ) { . 11 new new the Thread ( new new the Runnable () { 12 is @Override 13 is public void RUN () { 14 SELECT (); 15 } 16 }, "thread" + I) .start (); . 17 } 18 is } . 19 20 is / ** 21 is * query program 22 is * / 23 is public static void SELECT () { 24 connection Conn = null ; 25 the PreparedStatement pstmt = null ; 26 is the ResultSet RS = null ; 27 // get connection and executes the SQL 28 the try { 29 conn = pool.getConnection(); 30 pstmt = conn.prepareStatement("select * from student where id = 906"); 31 rs = pstmt.executeQuery(); 32 while (rs.next()) { 33 System.out.println(Thread.currentThread().getName() + "\t" + rs.getString(1) + "\t" + rs.getString(2) + "\t" + rs.getString("address")); 34 } 35 } catch (Exception e) { 36 e.printStackTrace(); 37 } finally { 38 // 释放资源 39 try { 40 rs.close(); 41 } catch (SQLException e) { 42 e.printStackTrace(); 43 } 44 try { 45 pstmt.close(); 46 } catch (SQLException e) { 47 e.printStackTrace(); 48 } 49 /* 50 try { 51 conn.close(); 52 } catch (SQLException e) { 53 e.printStackTrace(); 54 } 55 */ 56 pool.releaseConnection(conn); 57 } 58 } 59 }
Close method using dynamic linked agent modifies native
Improved Description
Simple database connection pool already, but when in use If you call the close method native, causes the connection can not be reused.
The use of dynamic proxy learned to improve before the release of resources is still the method of connecting calls to close the pool when the method of execution.
In DataPoolUtils add the relevant internal class dynamic proxy class tools:
1 /** 2 * 代理处理类 3 */ 4 class ConnectionInvocationHandler implements InvocationHandler{ 5 private Connection connection; 6 private DataPoolUtils dpu; 7 8 public ConnectionInvocationHandler(DataPoolUtils dpu, Connection connection) { 9 this.dpu = dpu; 10 this.connection = connection; 11 } 12 13 @Override 14 public Object invoke(Object proxy, Method method, Object[] args) 15 throws the Throwable { 16 // modify the native shutdown method . 17 IF (method.getName () the equals ( "Close." )) { 18 is dpu.releaseConnection (Connection); . 19 return null ; 20 is } the else { 21 is return Method .invoke (Connection, args); 22 is } 23 is } 24 }
Modify DataPoolUtils tools in the public Connection the getConnection () Returns the value of the method, it returns the value to the dynamic proxies:
1 return (Connection) Proxy.newProxyInstance( 2 this.getClass().getClassLoader(), 3 new Class[] { Connection.class }, 4 new ConnectionInvocationHandler(this, connection));
Modify TestPool service class public static void SELECT () method, the releasable connection to close the connection:
1 try { 2 conn.close(); 3 } catch (SQLException e) { 4 e.printStackTrace(); 5 }
Note Note
In the tools of the getConnection () Returns the proxy class method, instead of tools of the createConnection () returns the process, is because the object is to get the latter into the active queue , and if the agent return in the latter object, then it will lead to activity queue objects are proxy object .
So in the implementation of the proxy object close () when the method, after a dynamic proxy, the proxy object is actually being executed releaseConnection () method, which is to be idle proxy object into the queue from the active queue , but because the event queue They are stored in the proxy object, resulting not from the event queue proxy object through the proxy object placed on the idle queue , which led to the connection resources have not been recycled.