使用Proxy模拟一个最简单的数据库Connection池和PrepareStatment池

使用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);
}
2. 连接池实现类DBConnectionPool
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;
}
}
3. 拦截器类ConnectionHandler
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;
}

}
4. 测试类
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 **
从结果可以表明使用了缓存,第二次使用的是第一次缓存记录

你可能感兴趣的:(使用Proxy模拟一个最简单的数据库Connection池和PrepareStatment池)