您的位置:首页 > 编程语言 > Java开发

2018-07-24期 Java动态代理实现数据库连接池

2018-07-24 10:47 603 查看
package cn.sjq.proxy.ds.pool;
import java.io.PrintWriter;
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.sql.SQLFeatureNotSupportedException;
import java.util.LinkedList;
import java.util.logging.Logger;
import javax.sql.DataSource;
/**
* 使用Java 动态代理实现数据库连接池Pool
*
* @author songjq
*
*/
public class DataSourcePool implements DataSource {
// 驱动程序名
static String driver = "com.mysql.jdbc.Driver";
// URL指向要访问的数据库名mydata
static String url = "jdbc:mysql://hadoop-server03:3306/mysql";
// MySQL配置时的用户名
static String user = "root";
// MySQL配置时的密码
static String password = "user#0989";
// 定义一个链表保存20个数据库连接
static LinkedList<Connection> pool = new LinkedList<>();
// 静态代码块
static {
// 加载驱动程序
try {
Class.forName(driver);
for (int i = 0; i < 20; i++) {
pool.add(DriverManager.getConnection(url, user, password));
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public PrintWriter getLogWriter() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public int getLoginTimeout() throws SQLException {
// TODO Auto-generated method stub
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
// TODO Auto-generated method stub
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
// TODO Auto-generated method stub
return false;
}
/**
* 重写getConnection()方法
*/
@Override
public Connection getConnection() throws SQLException {
/*
* 如果pool长度大于0,说明pool存在连接,将第一个对象返回,否则抛出异常
*/
// 未使用动态代理前
/*
* if(pool.size()>0) { return pool.removeFirst(); }else { throw new
* SQLException("连接池已耗尽,无法分配新的连接..."); }
*/
/**
* 未使用动态代理前,客户端进行第21次连接的时候就抛出连接池已耗尽的异常,虽然使用conn.close()方法归还连接,但是该方法是将连接归还给数据库,而不是我们定义的pool对象
* 如果要实现调用conn.close()方法后将conn连接对象归还给pool连接池,就需要使用Java
* 动态代理重写Connection接口的close()方法。
* 这是客户端第19次获得数据库连接...,连接信息:com.mysql.jdbc.Connection@389922
* 这是客户端第20次获得数据库连接...,连接信息:com.mysql.jdbc.Connection@1cda81e Exception in
* thread "main" java.sql.SQLException: 连接池已耗尽,无法分配新的连接... at
* cn.sjq.proxy.ds.pool.DataSourcePool.getConnection(DataSourcePool.java:101) at
* cn.sjq.proxy.ds.pool.ClientTest.main(ClientTest.java:21)
*/
/**
* 下面使用动态代理重写Connection接口的close()方法,实现调用close()方法后归还DataSourcePool连接池的连接。 loader
* - 定义代理类的类加载器 interfaces - 代理类要实现的接口列表 h - 指派方法调用的调用处理程序
* 通过使用动态代理后客户端可以源源不断获得连接,而不是到达20个上限后抛出异常,如下:
* 这是客户端第25次获得数据库连接...,连接信息:com.mysql.jdbc.Connection@1cc5af0
* 这是客户端第26次获得数据库连接...,连接信息:com.mysql.jdbc.Connection@1665a0d
* 这是客户端第27次获得数据库连接...,连接信息:com.mysql.jdbc.Connection@a22e0c
* 这是客户端第28次获得数据库连接...,连接信息:com.mysql.jdbc.Connection@17d51a6
*/
if (pool.size() > 0) {
// 从pool里面获取一个连接对象Connection
final Connection conn = pool.removeFirst();
// 使用Java 动态代理重写Connection中close()方法
Connection newProxyConn = (Connection) Proxy.newProxyInstance(DataSourcePool.class.getClassLoader(),
conn.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 重写close方法
if (method.getName().equals("close")) {
// 回收释放连接
pool.add(conn);
return null;
} else {
// 其它方法不重写
return method.invoke(conn, args);
}
}
});
return newProxyConn;
} else {
throw new SQLException("连接池已耗尽,无法分配新的连接...");
}
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
// TODO Auto-generated method stub
return null;
}
}
package cn.sjq.proxy.ds.pool;
import java.sql.Connection;
import java.sql.SQLException;
/**
* 模拟客户端连接数据
* @author songjq
*
*/
public class ClientTest {
public static void main(String[] args) throws SQLException, InterruptedException {

int count = 0;
//实例化连接池对象DataSourcePool
DataSourcePool pool = new DataSourcePool();
//循环模拟连接数据库
while(true) {
//获得一个连接
Connection conn = pool.getConnection();
count++;
//打印连接信息
System.out.println("这是客户端第"+count+"次获得数据库连接...,连接信息:"+conn);
//关闭客户端连接,将连接归还连接池
conn.close();
//线程睡眠3秒
Thread.sleep(3000);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息