`
yy59750901
  • 浏览: 1636 次
  • 性别: Icon_minigender_1
  • 来自: 天津
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

写了一个简单的数据库连接池,请帮忙看一下

阅读更多
我是一个新手,第一次发帖,以前都是看别人的帖子。
我写了一个简单的数据库连接池实现,感觉有很多欠缺的地方,希望各位指点一下。十分感谢。
有四个类:
(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
分享到:
评论
17 楼 kimmking 2011-03-13  
yy59750901 写道
whaosoft 写道
支持一下 羊驼吧 大家记住啊  lz是可爱的 羊驼驼

我靠  你个大便男

我刚写了个简单的连接池。
等我花点时间写点原理性的东西,一起发出来。
16 楼 yy59750901 2011-03-13  
whaosoft 写道
支持一下 羊驼吧 大家记住啊  lz是可爱的 羊驼驼

我靠  你个大便男
15 楼 whaosoft 2011-03-12  
支持一下 羊驼吧 大家记住啊  lz是可爱的 羊驼驼
14 楼 kgd1120 2011-03-12  
客户端调用close方法会发生什么现象?returnConn是什么时候调用呢?

数据库连接池的核心之一是客户端透明,当客户端调用close方法时返还Connection对象
13 楼 kimmking 2011-03-12  
yy59750901 写道
javaso 写道
实现DataSource

多谢指点!!

连接池,首先可以控制资源个数,以后避免创建。
用完的资源,可以再放到池中使用。

支持多个线程并发获取资源。
池中满了,并且所有资源都处于忙的状态,
某个线程获取不用资源时,应该锁住线程,重试直到超时未知。

此外,某个资源,长期空闲,应该被回收掉。
定时检查资源是否已经不可用(connection isClosed),从池中去掉。

我一时能想到的,大概就这么多吧。
12 楼 yy59750901 2011-03-12  
javaso 写道
实现DataSource

多谢指点!!
11 楼 yy59750901 2011-03-12  
wing5jface 写道
如果使用的某一个数据库连接未归还,超过一定时间,没有相关的线程代码监控?

是是!!忘了!多谢
10 楼 kimmking 2011-03-12  
javaso 写道
实现DataSource

正解。。。。
9 楼 javaso 2011-03-12  
实现DataSource
8 楼 wing5jface 2011-03-12  
如果使用的某一个数据库连接未归还,超过一定时间,没有相关的线程代码监控?
7 楼 yy59750901 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);的机制我还没研究过。。
感觉很复杂 像写一个数据库驱动一样。。
6 楼 kimmking 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或其他连接池写了个程序,
替换成你的连接池,不需要改我原来的代码。
5 楼 yy59750901 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();就可以了。
4 楼 kimmking 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 


不知道我说的是不是你的意思。

明显不是我的意思。
前几天也有人发了一个连接池。跟你这个几乎一样。

3 楼 yy59750901 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 


不知道我说的是不是你的意思。
2 楼 chenchao051 2011-03-12  
kimmking 写道
个人觉得,一个数据库连接池,必须是非侵入性的,和jdbc本身兼容。

即我只需要把jdbc/datasource配置改成连接池的设置,
原来用jdbc写的代码什么都不用改。

比如只换掉一个jdbc driver类。


那必须的。。。。
1 楼 kimmking 2011-03-12  
个人觉得,一个数据库连接池,必须是非侵入性的,和jdbc本身兼容。

即我只需要把jdbc/datasource配置改成连接池的设置,
原来用jdbc写的代码什么都不用改。

比如只换掉一个jdbc driver类。

相关推荐

    易语言NetDB数据库操作中间件

    2、**本次更新的数据库池支持现在设定的多个数据库同时在线。 3、**优化链接数据库速度提升。 ================ [2020-1-5日] ================ 1、**修正服务端连续读数据时崩溃问题,感谢群友(无极)帮忙测试,...

    设计模式_简单易懂的例子,且很有意思

    当应用程序需要确保某些资源只被创建一次时,比如数据库连接池、日志对象等,可以使用单例模式。 **实现细节**: 单例模式可以通过构造器私有化、静态内部类等方式实现。 #### 四、多例模式 **定义**: 多例模式...

    MINA/JAVA游戏服务端源码

    db.jdbc:jdbc连接池 game:开始游戏 game.message:消息管理者,将客户端的消息传到具体的处理器处理 game.message.handler:消息处理者(功能实现的地方,上接service,下连DAO) net.mina.protocol:自定义通信...

    Java设计模式经典搞笑珍藏版

    这种模式常用于创建数据库连接池、线程池等共享资源。 #### 五、多例模式(Multiton Pattern) 多例模式是单例模式的一种变体,允许根据不同的参数返回不同的实例。这通常用于需要根据某种条件创建不同实例的情况。...

    java24种设计模式介绍与6大设计原则

    这种模式常用于日志记录、数据库连接池、线程池等场景,以避免资源浪费和提高性能。 ##### 4. **多例模式【Multiton Pattern】** 多例模式是单例模式的一个变体,它允许一个类有多个实例,并且可以根据某种标识...

    java设计模式

    - **应用场景**:数据库连接池、日志对象等。 - **多例模式(Multiton Pattern)** - **定义**:与单例模式类似,但允许有多个实例。 - **应用场景**:用户设置等,每个用户可以有自己的配置。 - **抽象工厂模式...

    C++设计模式

    在很多情况下,我们希望整个系统中只有一个特定的对象存在,例如数据库连接池、线程池等。此时,单例模式就能派上用场。 #### 实现 实现一个简单的单例类: ```cpp class Singleton { private: static Singleton...

    Java设计模式面试实用

    **案例**:假设需要创建一个数据源管理器的多例,根据不同的数据库名称创建对应的连接池。 ```java import java.util.HashMap; import java.util.Map; public class DataSourceManager { private static final ...

    java设计模式1

    在多线程环境中,我们需要确保某些资源只能被一个线程访问,例如数据库连接池、日志记录器等。 1. **懒汉式单例模式**: ```java public class Singleton { private static Singleton instance; private ...

Global site tag (gtag.js) - Google Analytics