锁定老帖子 主题:写了一个简单的数据库连接池,请帮忙看一下
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-03-12
我写了一个简单的数据库连接池实现,感觉有很多欠缺的地方,希望各位指点一下。十分感谢。 有四个类: (1)连接池配置对象 Config (2)连接池主类 ConnectionPool (3)Properties读取类 PropertyReader (4)异常类 DBPoolException ConnectionPool.java public class ConnectionPool { private static Logger logger = Logger.getLogger(ConnectionPool.class); //当前已用连接数 private static volatile int curConnections = 0; private static Config config = null; //初始化成功标志 private static boolean initFlag = false; private static volatile Stack<Connection> conns; static { PropertyReader pr = null; try { pr = new PropertyReader("pool-config.properties"); config = new Config(); //设置数据库驱动 config.setDriver(pr.getValue("driver")); //url config.setUrl(pr.getValue("url")); //uername config.setUsername(pr.getValue("username")); //password config.setPassword(pr.getValue("password")); //最大连接数 if(pr.getValue("maxConnections") != null){ config.setMaxConnections(Integer.valueOf(pr.getValue("maxConnections"))); } //初始化时最小连接数 if(pr.getValue("minConnections") != null){ config.setMinConnections(Integer.valueOf(pr.getValue("minConnections"))); } //返还连接时是否提交 if(pr.getValue("autoCommitOnClose") != null){ config.setAutoCommitOnClose(Boolean.valueOf(pr.getValue("autoCommitOnClose"))); } //当连接池用完时客户端调用getConn()后等待获取新连接的时间 //Default: (100毫秒) if(pr.getValue("checkoutTimeout") != null){ config.setCheckoutTimeout(Integer.valueOf(pr.getValue("checkoutTimeout"))); } //当没有可用链接时,尝试获取链接的次数 if(pr.getValue("checkTimes") != null){ config.setCheckTimes(Integer.valueOf(pr.getValue("checkTimes"))); } initPool(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } /** * 隐藏构造函数 */ private ConnectionPool(){ } /** * 初始化连接池 保存minConnections个链接 * @throws SQLException * @throws ClassNotFoundException */ private static synchronized void initPool() throws SQLException, ClassNotFoundException{ conns = new Stack<Connection>(); Class.forName(config.getDriver()); for(int i = 0 ; i < config.getMinConnections() ; i++){ Connection conn = newConnection(); conns.push(conn); } initFlag = true; } /** * 获取一个可用链接 * @return * @throws SQLException * @throws InterruptedException * @throws DBPoolException * @throws Exception */ public static Connection getConn() throws SQLException, InterruptedException, DBPoolException { Connection conn = null; if (initFlag) { synchronized (conns) { // 循环次数 int times = 0; while (null == conn && times < config.getCheckTimes() + 1) { times++; // 如果未达到最大链接 if (curConnections < config.getMaxConnections()) { // 栈中未空 if (!conns.isEmpty()) { conn = conns.pop(); // 如果返回的链接不可用 if (null == conn || conn.isClosed()) { conn = newConnection(); } // 栈中空了 } else { conn = newConnection(); } } else { conns.wait(config.getCheckoutTimeout()); } } if(null == conn){ logger.warn("获取链接超时!!!!!"); throw new DBPoolException("获取链接超时!!!!!"); }else{ curConnections++; conns.notifyAll(); } } } else { logger.error("连接池初始化失败!!!!"); throw new DBPoolException("连接池初始化失败!!!!"); } return conn; } /** * 归还一个链接 * @param conn * @throws SQLException * @throws InterruptedException */ public static void returnConn(Connection conn) throws SQLException, InterruptedException { synchronized (conns) { if (null != conn && !conn.isClosed()) { // 如果设置归还前自动提交为真 if (config.isAutoCommitOnClose()) { conn.commit(); } else { conn.rollback(); } } int times = 0; //尝试归还5次 如果归还失败则关闭连接 while (times < 6) { times++; if (curConnections > 0 && curConnections <= config.getMaxConnections()) { conns.push(conn); curConnections--; break; } else if (curConnections == 0) { conns.wait(1000); } else { if(conn!=null && !conn.isClosed()) conn.close(); curConnections--; break; } } if(times == 5 && conn != null && !conn.isClosed()){ conn.close(); } conns.notifyAll(); } } /** * 简单的创建一个链接 * @return * @throws SQLException */ private static Connection newConnection() throws SQLException{ return DriverManager.getConnection(config.getUrl(),config.getUsername(),config.getPassword()); } /** * 获取已使用的连接数 * @return */ public static int getCurConnections() { return curConnections; } } Config.java public class Config { private String driver; private String url; private String username; private String password; private int minConnections = 10; private int maxConnections = 20; private boolean autoCommitOnClose = true; private int checkoutTimeout = 100; private int checkTimes = 10; public String getDriver() { return driver; } public void setDriver(String driver) { this.driver = driver; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public int getMinConnections() { return minConnections; } public void setMinConnections(int minConnections) { this.minConnections = minConnections; } public int getMaxConnections() { return maxConnections; } public void setMaxConnections(int maxConnections) { this.maxConnections = maxConnections; } public boolean isAutoCommitOnClose() { return autoCommitOnClose; } public void setAutoCommitOnClose(boolean autoCommitOnClose) { this.autoCommitOnClose = autoCommitOnClose; } public int getCheckoutTimeout() { return checkoutTimeout; } public void setCheckoutTimeout(int checkoutTimeout) { this.checkoutTimeout = checkoutTimeout; } public int getCheckTimes() { return checkTimes; } public void setCheckTimes(int checkTimes) { this.checkTimes = checkTimes; } } PropertyReader.java public class PropertyReader { Logger log = Logger.getLogger(PropertyReader.class); Properties props = null; public PropertyReader(String path) throws IOException{ props = new Properties(); try { props.load(getClass().getClassLoader().getResourceAsStream(path)); } catch (IOException e) { log.error("读取properties失败"); throw e; } } public String getValue(String key){ return props.getProperty(key); } } DBPoolException .java public class DBPoolException extends Throwable { public DBPoolException(String str){ super(str); } } properties配置文件 driver=oracle.jdbc.driver.OracleDriver url=jdbc:oracle:thin:@localhost:1521:orcl username=test password=password minConnections=10 maxConnections=30 #当链接关闭的时候自动将未提交的内容提交 autoCommitOnClose=false #当连接池用完时客户端调用getConn()后等待获取新连接的时间,Default: (100毫秒) checkoutTimeout=100 #当没有可用链接时,尝试获取链接的次数 checkTimes=30 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2011-03-12
个人觉得,一个数据库连接池,必须是非侵入性的,和jdbc本身兼容。
即我只需要把jdbc/datasource配置改成连接池的设置, 原来用jdbc写的代码什么都不用改。 比如只换掉一个jdbc driver类。 |
|
返回顶楼 | |
发表时间:2011-03-12
kimmking 写道 个人觉得,一个数据库连接池,必须是非侵入性的,和jdbc本身兼容。
即我只需要把jdbc/datasource配置改成连接池的设置, 原来用jdbc写的代码什么都不用改。 比如只换掉一个jdbc driver类。 那必须的。。。。 |
|
返回顶楼 | |
发表时间:2011-03-12
kimmking 写道 个人觉得,一个数据库连接池,必须是非侵入性的,和jdbc本身兼容。
即我只需要把jdbc/datasource配置改成连接池的设置, 原来用jdbc写的代码什么都不用改。 比如只换掉一个jdbc driver类。 首先 谢谢你的耐心观看 和 回复 我是通过properties来改变数据库的driver,就在最下面的properties配置文件中,如下: driver=oracle.jdbc.driver.OracleDriver url=jdbc:oracle:thin:@localhost:1521:orcl username=test password=password minConnections=10 maxConnections=30 #当链接关闭的时候自动将未提交的内容提交 autoCommitOnClose=false #当连接池用完时客户端调用getConn()后等待获取新连接的时间,Default: (100毫秒) checkoutTimeout=100 #当没有可用链接时,尝试获取链接的次数 checkTimes=30 不知道我说的是不是你的意思。 |
|
返回顶楼 | |
发表时间:2011-03-12
yy59750901 写道 kimmking 写道 个人觉得,一个数据库连接池,必须是非侵入性的,和jdbc本身兼容。
即我只需要把jdbc/datasource配置改成连接池的设置, 原来用jdbc写的代码什么都不用改。 比如只换掉一个jdbc driver类。 首先 谢谢你的耐心观看 和 回复 我是通过properties来改变数据库的driver,就在最下面的properties配置文件中,如下: driver=oracle.jdbc.driver.OracleDriver url=jdbc:oracle:thin:@localhost:1521:orcl username=test password=password minConnections=10 maxConnections=30 #当链接关闭的时候自动将未提交的内容提交 autoCommitOnClose=false #当连接池用完时客户端调用getConn()后等待获取新连接的时间,Default: (100毫秒) checkoutTimeout=100 #当没有可用链接时,尝试获取链接的次数 checkTimes=30 不知道我说的是不是你的意思。 明显不是我的意思。 前几天也有人发了一个连接池。跟你这个几乎一样。 |
|
返回顶楼 | |
发表时间:2011-03-12
kimmking 写道 yy59750901 写道 kimmking 写道 个人觉得,一个数据库连接池,必须是非侵入性的,和jdbc本身兼容。
即我只需要把jdbc/datasource配置改成连接池的设置, 原来用jdbc写的代码什么都不用改。 比如只换掉一个jdbc driver类。 首先 谢谢你的耐心观看 和 回复 我是通过properties来改变数据库的driver,就在最下面的properties配置文件中,如下: driver=oracle.jdbc.driver.OracleDriver url=jdbc:oracle:thin:@localhost:1521:orcl username=test password=password minConnections=10 maxConnections=30 #当链接关闭的时候自动将未提交的内容提交 autoCommitOnClose=false #当连接池用完时客户端调用getConn()后等待获取新连接的时间,Default: (100毫秒) checkoutTimeout=100 #当没有可用链接时,尝试获取链接的次数 checkTimes=30 不知道我说的是不是你的意思。 明显不是我的意思。 前几天也有人发了一个连接池。跟你这个几乎一样。 啊。。是么。。。 那你的意思我没太明白,像我这样,只要把各种数据库的驱动放进去,然后通过修改properties不就能达到变换数据库的作用么,取得连接只需要 ConnectionPool.getConn();就可以了。 |
|
返回顶楼 | |
发表时间:2011-03-12
yy59750901 写道 kimmking 写道 yy59750901 写道 kimmking 写道 个人觉得,一个数据库连接池,必须是非侵入性的,和jdbc本身兼容。
即我只需要把jdbc/datasource配置改成连接池的设置, 原来用jdbc写的代码什么都不用改。 比如只换掉一个jdbc driver类。 首先 谢谢你的耐心观看 和 回复 我是通过properties来改变数据库的driver,就在最下面的properties配置文件中,如下: driver=oracle.jdbc.driver.OracleDriver url=jdbc:oracle:thin:@localhost:1521:orcl username=test password=password minConnections=10 maxConnections=30 #当链接关闭的时候自动将未提交的内容提交 autoCommitOnClose=false #当连接池用完时客户端调用getConn()后等待获取新连接的时间,Default: (100毫秒) checkoutTimeout=100 #当没有可用链接时,尝试获取链接的次数 checkTimes=30 不知道我说的是不是你的意思。 明显不是我的意思。 前几天也有人发了一个连接池。跟你这个几乎一样。 啊。。是么。。。 那你的意思我没太明白,像我这样,只要把各种数据库的驱动放进去,然后通过修改properties不就能达到变换数据库的作用么,取得连接只需要 ConnectionPool.getConn();就可以了。 我的意思是,我现在用jdbc或其他连接池写了个程序, 替换成你的连接池,不需要改我原来的代码。 |
|
返回顶楼 | |
发表时间:2011-03-12
kimmking 写道 yy59750901 写道 kimmking 写道 yy59750901 写道 kimmking 写道 个人觉得,一个数据库连接池,必须是非侵入性的,和jdbc本身兼容。
即我只需要把jdbc/datasource配置改成连接池的设置, 原来用jdbc写的代码什么都不用改。 比如只换掉一个jdbc driver类。 首先 谢谢你的耐心观看 和 回复 我是通过properties来改变数据库的driver,就在最下面的properties配置文件中,如下: driver=oracle.jdbc.driver.OracleDriver url=jdbc:oracle:thin:@localhost:1521:orcl username=test password=password minConnections=10 maxConnections=30 #当链接关闭的时候自动将未提交的内容提交 autoCommitOnClose=false #当连接池用完时客户端调用getConn()后等待获取新连接的时间,Default: (100毫秒) checkoutTimeout=100 #当没有可用链接时,尝试获取链接的次数 checkTimes=30 不知道我说的是不是你的意思。 明显不是我的意思。 前几天也有人发了一个连接池。跟你这个几乎一样。 啊。。是么。。。 那你的意思我没太明白,像我这样,只要把各种数据库的驱动放进去,然后通过修改properties不就能达到变换数据库的作用么,取得连接只需要 ConnectionPool.getConn();就可以了。 我的意思是,我现在用jdbc或其他连接池写了个程序, 替换成你的连接池,不需要改我原来的代码。 明白点你的意思了 。。。 是说普通jdbc: CLass.forName(driver); 现在我写一个类似driver的东西么?加载这个driver之后 原来的 DriverManager.getConnection(url,name,password); 取得就是我这个driver弄出来的一个连接? 这个确实很高深!! DriverManager.getConnection(url,name,password);的机制我还没研究过。。 感觉很复杂 像写一个数据库驱动一样。。 |
|
返回顶楼 | |
发表时间:2011-03-12
最后修改:2011-03-12
如果使用的某一个数据库连接未归还,超过一定时间,没有相关的线程代码监控?
|
|
返回顶楼 | |
发表时间:2011-03-12
实现DataSource
|
|
返回顶楼 | |