写了个简单的连接池 不知道是不是这个意思

BearKin 2010-09-14 02:54:43
ConnectionPool.java


package com.lv9.jdbc;

import java.io.FileInputStream;
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.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;

public class ConnectionPool {
private volatile LinkedList<Connection> connectionPool = new LinkedList<Connection>();

private final String userName;
private final String password;
private final String driverName;
private final String connectionURL;
private final String databaseName;
private final int maxFreeConnectionsSize;

private int poolSize;

private static ConnectionPool pool;

private ConnectionPool() throws Exception {
Properties properties = new Properties();

properties.load(new FileInputStream(getClass().getResource("")
.getPath()
+ "database.properties"));

this.userName = properties.getProperty("userName");
this.password = properties.getProperty("password");
this.driverName = properties.getProperty("driverName");
this.connectionURL = properties.getProperty("connectionURL");
this.databaseName = properties.getProperty("databaseName");
this.maxFreeConnectionsSize = Integer.parseInt(properties
.getProperty("maxFreeConnectionsSize"));
this.poolSize = Integer.parseInt(properties.getProperty("poolSize"));

init();
}

public synchronized static ConnectionPool getConnectionPool()
throws Exception {
if (pool == null) {
pool = new ConnectionPool();
}
return pool;
}

public int executeUpdate(String sql) throws Exception {
Connection connection = null;
try {
connection = getConnection();
Statement statement = connection.createStatement();

return statement.executeUpdate(sql);
} finally {
if (connection != null) {
connection.close();
}
}
}

public List<?> executeQuery(String sql) throws Exception {
List<?> result = null;

Connection connection = null;
Statement statement = null;
ResultSet rs = null;
try {
connection = getConnection();
statement = connection.createStatement();
rs = statement.executeQuery(sql);

ResultSetMetaData metaData = rs.getMetaData();

int columnCount;

if ((columnCount = metaData.getColumnCount()) > 1) {
result = getSingleList(rs);
} else {
result = getList(rs, columnCount);
}
} finally {
if (rs != null) {
rs.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
}

return result;
}

public synchronized Connection getConnection() throws Exception {
Connection connection;
if (connectionPool.isEmpty()) {
System.out.println("创建连接");
poolSize++;
connection = getProxyConnection();
} else {
connection = connectionPool.removeFirst();
}
return connection;
}

public String getDataBaseName() {
return databaseName;
}

protected int getMaxFreeConnectionSize() {
return maxFreeConnectionsSize;
}

protected int getFreeConnectionCount() {
return connectionPool.size();
}

protected synchronized void removeAConnection() {
poolSize--;
}

protected int getPoolSize() {
return poolSize;
}

protected synchronized void resetConnection(Connection connection) {
connectionPool.addLast(connection);
}

private void init() throws Exception {
Class.forName(driverName);
for (int i = 0; i < poolSize; i++) {
connectionPool.addFirst(getProxyConnection());
}
}

private Connection getProxyConnection() throws Exception {
PoolConnection invocationHandlerObject = new PoolConnection(
getDataBaseConnection(), this);

return (Connection) Proxy.newProxyInstance(this.getClass()
.getClassLoader(), new Class<?>[] { Connection.class },
invocationHandlerObject);

}

private Connection getDataBaseConnection() throws Exception {
return DriverManager.getConnection(connectionURL, userName, password);
}

private List<Object[]> getList(ResultSet rs, int columnCount)
throws Exception {
List<Object[]> list = new ArrayList<Object[]>();
while (rs.next()) {
Object[] objs = new Object[columnCount];
for (int i = 1; i <= columnCount; i++) {
objs[i - 1] = rs.getObject(i);
}
list.add(objs);
}
return list;
}

private List<Object> getSingleList(ResultSet rs) throws Exception {
List<Object> list = new ArrayList<Object>();
while (rs.next()) {
list.add(rs.getObject(1));
}
return list;
}
}

class PoolConnection implements InvocationHandler {
private Connection connection;
private ConnectionPool pool;

public PoolConnection(Connection connection, ConnectionPool pool) {
this.connection = connection;
this.pool = pool;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if (method.getName().trim().equals("close")) {
System.out.println(this + " : 已经重置.当前连接池内连接数为:"
+ pool.getPoolSize() + ". 当前空闲连接有:"
+ pool.getFreeConnectionCount());
if (pool.getFreeConnectionCount() < pool.getMaxFreeConnectionSize()) {
pool.resetConnection((Connection) proxy);
} else {
method.invoke(connection, args);
pool.removeAConnection();
}

return null;
} else {
return method.invoke(connection, args);
}
}
}
...全文
148 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
BearKin 2010-10-06
  • 打赏
  • 举报
回复
package com.java.lv9.jdbc;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

public class ConnectionPoolProperties {

private String userName; // 用户名
private String password;// 密码
private String driverName;// 驱动
private String connectionURL;// 连接地址
private String databaseName;// 驱动
private int maxConnectionsSize;// 最大连接
private int initPoolSize;// 初始化连接
private long connectionUpdateInterval;// 连接更新间隔时间
private boolean isWaitingFreeConnection;// 是否等待空闲连接 默认为false 如果是的话

// 当连接池没有连接的时候 等待回收的连接

public ConnectionPoolProperties(FileInputStream in) {
Properties properties = new Properties();

try {
properties.load(in);

this.userName = properties.getProperty("userName");
this.password = properties.getProperty("password");
this.driverName = properties.getProperty("driverName");
this.connectionURL = properties.getProperty("connectionURL");
this.databaseName = properties.getProperty("databaseName");
this.maxConnectionsSize = Integer.parseInt(properties.getProperty("maxConnectionsSize"));
this.isWaitingFreeConnection = Boolean.parseBoolean(properties.getProperty("isWaitingFreeConnection"));
this.initPoolSize = Integer.parseInt(properties.getProperty("initPoolSize"));
this.connectionUpdateInterval = Long.parseLong(properties.getProperty("connectionUpdateInterval")) * 1000 * 60;
} catch (IOException e) {
throw new RuntimeException(e);
}
}

public String getUserName() {
return userName;
}

public String getPassword() {
return password;
}

public String getDriverName() {
return driverName;
}

public String getConnectionURL() {
return connectionURL;
}

public String getDatabaseName() {
return databaseName;
}

public int getMaxConnectionsSize() {
return maxConnectionsSize;
}

public int getInitPoolSize() {
return initPoolSize;
}

public long getConnectionUpdateInterval() {
return connectionUpdateInterval;
}

public boolean isWaitingFreeConnection() {
return isWaitingFreeConnection;
}

}

dinghun8leech 2010-10-06
  • 打赏
  • 举报
回复
向果子学习,哈哈。
dbcp连接池就有这个问题,八小时一过,所有的连接全歇菜。
eggno8 2010-09-17
  • 打赏
  • 举报
回复
学习了~mark
BearKin 2010-09-17
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 bao110908 的回复:]

如果需要自己实现一个连接池的话,最起码得对这些技术灵活运用:
* JDBC(java.sql.*, javax.sql.*)
* 线程处理、定时任务
* 动态代理(java.lang.reflect.Proxy, java.lang.reflect.InvocationHandler)
* 集合(java collection framework)

用到的 Java……
[/Quote]

谢谢果子大哥指导 看了您说的 第一个和第三个大概是实现了的(。。大概 虽然不是用守护线程)

好吧 俺承认俺都没实现。。 俺会从新写个的 再次感谢
BearKin 2010-09-17
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 dinghun8leech 的回复:]

是得在finally里来三个try catch呀。嫌难看可以拉个帘子。
获取连接和还回连接这两个操作需要同步,我想是不是有更好的解决办法。
[/Quote]

拉帘子。。
  • 打赏
  • 举报
回复
如果需要自己实现一个连接池的话,最起码得对这些技术灵活运用:
* JDBC(java.sql.*, javax.sql.*)
* 线程处理、定时任务
* 动态代理(java.lang.reflect.Proxy, java.lang.reflect.InvocationHandler)
* 集合(java collection framework)

用到的 Java 技术基本上就是这些了。

我草拟了一些连接池实现中主要的技术难点(个人观点仅供参考):

1:Connection#close 问题。使用者使用连接池与不使用连接池,除了从哪获得 Connection 对象不一样之外,其他 JDBC 的代码是完全相同的,并不能因为使用连接池而改变既有的 JDBC 代码。如果不能改变 JDBC 代码,就带来了一个 Connection close 的问题,大家都知道这个调用是关闭数据库连接,如果在连接池中这么做的话就会关闭连接,使用连接得不到重用。

解决方案:
1. 动态代理重写 close 方法,将其改为把连接还回到池中去;
2. 使用装饰器模式重写 close 方法,其他方法进行委托调用。

2:连接被动关闭问题。为了保证连接的复用性,将连接一直保存在池中。有些数据库服务器会将已经连接很久的客户端连接主动踢掉,如果碰到这种情况,在池中的这个连接池就会变为不可用状态,如果被客户端使用的话将会抛出连接被关闭的 SQLException。

解决方案:
使用一个守护线程定时地检查池中连接的健康状态,如果是不健康的连接就将其抛弃,重新生成一个放回池中以便补充。

3:连接回收问题。假如我们的连接池最大设为 50 个,在某一并发很高的时段达到了 50 个,但是过后并发率就降下去了,对于连接池来说池中还是 50 个连接,实际上后面根本不需要那么多连接。这时连接池白白地浪费了几十个数据库宝贵的连接(数据库对于客户端的连接数是有限制的),如果连接池占用了很多的连接,那么可能会导致其他应用程序因为数据库客户端的连接数到了限制而无法再获得连接。我们应该及时地将不需要使用的连接关闭还给数据库服务器,保留一些基本连接数。

解决方案:
配置连接池最大和最小的连接数,以及最大的空闲时间。使用一个守护线程定时查询池中哪些连接空闲的时间已经超过了配置的空闲时间时,就将其取出关闭还给数据库,这时如果池中连接数小于配置最小的连接数时,由这个守护线程打开几个连接填充到池中去。

4:网络中断重连问题。连接池中的连接在网络中断时,池中连接会全部断开,数据库服务端也会回收断开的连接。但是网络中断后,过了一些时间又连上了,这时池中的连接依然是断开的,如果取出来用的话,不用说就会抛出异常的。一个优秀的连接池,必须实现自动重连功能,否则就没有可用的价值。

解决方案:
与问题 1 的解决方案类似,但是这个线程应在网络中断时尝试关闭连接,并扔掉池中连接,启动网络连接监测直到网络通信恢复为止,当一监测到恢复时,立即从数据库中获得连接填充连接池。

--------------------------------------------------------------------
总之,要自己实现一个可用、高效的连接池,难度非常大。就算是著名的 Apache Commons DBCP 连接池实际在某些地方也是不尽如人意的。
dinghun8leech 2010-09-16
  • 打赏
  • 举报
回复
是得在finally里来三个try catch呀。嫌难看可以拉个帘子。
获取连接和还回连接这两个操作需要同步,我想是不是有更好的解决办法。
BearKin 2010-09-14
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 dinghun8leech 的回复:]
我原来也写过类似的玩意,不过有个疑问,获取连接和还回连接两步操作除了用synchronized之外,还有什么更高效而又安全的办法?
大致看下程序,发现一处问题,如果关闭rs出错,stmt和con都会因为exception的提前抛出到调用端,而没法释放。
[/Quote]

异常的问题果子大哥已经跟我说过了 说那样关闭不好 不过如果想让他完美关闭的话 除非每个你都try catch

那多难看啊


没感觉哪里不高效 没明白哦
dinghun8leech 2010-09-14
  • 打赏
  • 举报
回复
我原来也写过类似的玩意,不过有个疑问,获取连接和还回连接两步操作除了用synchronized之外,还有什么更高效而又安全的办法?
大致看下程序,发现一处问题,如果关闭rs出错,stmt和con都会因为exception的提前抛出到调用端,而没法释放。
BearKin 2010-09-14
  • 打赏
  • 举报
回复
为啥会沉谭呢
菖蒲老先生 2010-09-14
  • 打赏
  • 举报
回复
高手,要我写我肯定写不出来,太共通的东西都用的别人的。。。
flybird 2010-09-14
  • 打赏
  • 举报
回复
看到了
也学习下了。
BearKin 2010-09-14
  • 打赏
  • 举报
回复
下午无事写的 异常阿 注释阿 过段时间再补充。。
BearKin 2010-09-14
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 flybird 的回复:]

我平时用的思想上也差不多了。

不过一般连接池都有一个最大连接数,
超过了我们一般等待释放。不创建新连接了。
[/Quote]
我之前没有做过 所以我不太明白该做些什么

我这个跟你的区别是 不等待释放 而是创建 然后当用户释放连接的时候 用最大空闲连接数于当前空闲连接数对比 如果大于最大空闲连接数 我就关闭掉该连接了

有空的话可以运行下TestConnectionPool
flybird 2010-09-14
  • 打赏
  • 举报
回复
不好意思 刚刚没仔细看。
flybird 2010-09-14
  • 打赏
  • 举报
回复
我平时用的思想上也差不多了。

不过一般连接池都有一个最大连接数,
超过了我们一般等待释放。不创建新连接了。
BearKin 2010-09-14
  • 打赏
  • 举报
回复
平常大家用的连接池都是这样实现的么?
BearKin 2010-09-14
  • 打赏
  • 举报
回复
TestConnectionPool.java


package com.lv9.jdbc;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestConnectionPool {

public static void main(String[] args) throws Exception {
ExecutorService service = Executors.newCachedThreadPool();
for (int i = 0; i < 100; i++) {
service.submit(new TestConnectPoolThread());
}
}
}

class TestConnectPoolThread extends Thread {
public Random random = new Random();

public void run() {
while (true) {
try {
Thread.sleep(Math.abs(random.nextInt() % 200));
} catch (InterruptedException e1) {
e1.printStackTrace();
}
ConnectionPool connectionPool;
try {
connectionPool = ConnectionPool.getConnectionPool();
connectionPool
.executeQuery("SELECT * FROM mytable m LIMIT 0,1000");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
BearKin 2010-09-14
  • 打赏
  • 举报
回复
database.properties


driverName=com.mysql.jdbc.Driver
userName=root
password=1234
databaseName=mysql
connectionURL=jdbc\:mysql\://127.0.0.1\:3306/mydatabase?useUnicode\=true&characterEncoding\=gbk
poolSize=10
maxFreeConnectionsSize=10

50,528

社区成员

发帖
与我相关
我的任务
社区描述
Java相关技术讨论
javaspring bootspring cloud 技术论坛(原bbs)
社区管理员
  • Java相关社区
  • 小虚竹
  • 谙忆
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧