使用Proxy模擬一個最簡單的數據庫Connection池和PrepareStatment池
今天在看夏欣老師的《深入淺出Hibernate》的時候,覺得老師在講數據庫連接池的時候的例子很不錯,使用Java動態代理實現對Connection攔截從而讓應用者使用連接池的時候不會因為手賤將Connection給關閉了,代碼如下:1. 連接池接口類ConnectionPool
package com.snippnet.pool;
import java.sql.Connection;
public interface ConnectionPool
{
Connection getConnection();
boolean releaseConnection(Connection proxy, Connection connection);
}
package com.snippnet.pool;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.collections.CollectionUtils;
public class DBConnectionPool implements ConnectionPool
{
private List<Connection> connections;
private int size; //最大容量
static {
try
{
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e)
{
e.printStackTrace();
}
}
public DBConnectionPool(int size)
{
this.size = size;
connections = new ArrayList<Connection>();
}
public synchronized Connection getConnection()
{
Connection connection = null;
if (CollectionUtils.isEmpty(connections))
{
try
{
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jira", "root", "root");
ConnectionHandler handler = new ConnectionHandler(this, connection);
// connection = (Connection)Proxy.newProxyInstance(this.getClass().getClassLoader(), connection.getClass().getInterfaces(), (InvocationHandler) handler);
connection = handler.bind(connection);
// connections.add(connection);
} catch (SQLException e)
{
e.printStackTrace();
}
} else
{
connection = connections.get(connections.size() - 1);
connections.remove(connections.size() - 1);
}
return connection;
}
public synchronized boolean releaseConnection(Connection proxy, Connection connection)
{
boolean bool = false;
if (connections != null)
{
if (connections.size() < (this.size - 1))
{
connections.add(proxy);
bool = true;
} else
{
try
{
if (!connection.isClosed())
{
connection.close();
}
bool = true;
} catch (SQLException e)
{
bool = false;
}
}
}
return bool;
}
}
package com.snippnet.pool;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class ConnectionHandler implements InvocationHandler
{
private ConnectionPool pool;
private Connection connection;
private Map<String, PreparedStatement> pstPool;
public ConnectionHandler(ConnectionPool pool, Connection connection)
{
this.pool = pool;
this.connection = connection;
this.pstPool = Collections.synchronizedMap(new HashMap<String, PreparedStatement>());
}
public Connection bind(Connection connection)
{
this.connection = connection;
return (Connection) Proxy.newProxyInstance(connection.getClass().getClassLoader()
, new Class[]{Connection.class}
, this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
Object obj = null;
if ("close".equals(method.getName()))
{
// 若為close方法
obj = pool.releaseConnection((Connection)proxy, connection);
}
else if ("prepareStatement".equals(method.getName()))
{
if (pstPool.containsKey((String)args[0]))
{
obj = pstPool.get((String)args[0]);
} else
{
String sql = (String)args[0];
obj = connection.prepareStatement(sql);
PrepareStatementHandler handler = new PrepareStatementHandler();
obj = handler.bind((PreparedStatement)obj);
pstPool.put(sql, (PreparedStatement)obj);
}
}
else
{
// 不為close方法
obj = method.invoke(connection, args);
}
return obj;
}
}
package com.snippnet.pool;
import java.sql.Connection;
import java.sql.PreparedStatement;
public class DynamicConnectionPoolTest
{
public static void main(String[] args) throws Exception
{
ConnectionPool pool = new DBConnectionPool(2);
Connection con = pool.getConnection();
PreparedStatement pst = con.prepareStatement("SELECT id FROM cwd_group WHERE id = ?");
System.out.println(con);
System.out.println(pst);
con.close();
Connection con1 = pool.getConnection();
System.out.println(con1);
PreparedStatement pst2 = con1.prepareStatement("SELECT id FROM cwd_group WHERE id = ?");
System.out.println(pst2);
con.close();
}
}
代碼功能很簡單,但麻雀雖小五臟俱全。
當Connection容量設置為1時候,執行結果:
com.mysql.jdbc.JDBC4Connection@6276e5
com.mysql.jdbc.JDBC4PreparedStatement@edeea8: SELECT id FROM cwd_group WHERE id = ** NOT SPECIFIED **
com.mysql.jdbc.JDBC4Connection@1d44ae9
com.mysql.jdbc.JDBC4PreparedStatement@823618: SELECT id FROM cwd_group WHERE id = ** NOT SPECIFIED **
從結果可以表明沒有使用緩存,每次都是取最新的記錄當Connection容量設置為2時候,執行結果:
com.mysql.jdbc.JDBC4Connection@6276e5
com.mysql.jdbc.JDBC4PreparedStatement@edeea8: SELECT id FROM cwd_group WHERE id = ** NOT SPECIFIED **
com.mysql.jdbc.JDBC4Connection@6276e5
com.mysql.jdbc.JDBC4PreparedStatement@edeea8: SELECT id FROM cwd_group WHERE id = ** NOT SPECIFIED **
從結果可以表明使用了緩存,第二次使用的是第一次緩存記錄
posted @ 2015-04-13 23:33 編程小強 閱讀(277) | 評論 (0) | 編輯 收藏