数据库连接池实现原理

本文介绍数据库连接池的实现原理及步骤,包括使用动态代理技术管理连接的借用与归还过程,探讨了开源连接池如DBCP和C3P0的工作方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数据库连接池实现原理

 实现原理是用动态代理技术

 

编写连接池需实现java.sql.DataSource接口,
 DataSource接口中定义了两个重载的getConnection方法:
 Connection getConnection()
 Connection getConnection(String username, String password)

 

public class JdbcPool implements DataSource {

	private static String driver;
	private static String url;
	private static  String username;
	private static String password;

	static{
		try {
			
			Properties prop = new Properties();
			InputStream in = JdbcUtil.class.getClassLoader().getResourceAsStream("db.properties");
			prop.load(in);
			driver = prop.getProperty("driver");
			url = prop.getProperty("url");
			username = prop.getProperty("username");
			password = prop.getProperty("password");
			Class.forName(driver);
		} catch (Exception e) {
			throw new ExceptionInInitializerError(e);
		}
	}
	
	private static LinkedList<Connection> pool = new LinkedList<Connection>();
	private static int poolsize = 10;
	//问题:每次newJdbcPoll都会建立10个链接,可使用单态设计模式解决此类问题
	public JdbcPool(){
	
		for(int i=0;i<poolsize;i++){
			try {
				Connection conn = DriverManager.getConnection(url,username,password);
				pool.add(conn);
				System.out.println(conn + "被加到池里面了!!!");
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	
	/*
	 * 这里使用动态代理技术返回一个假的Connection,当dao调用假connection的任何方法时,该方法体内会调用InvocationHandler.invoke方法
	 * 在invoke方法体内,发现dao调用的是close方法,则把链接还到池里,否则,调用真connection的对应方法。
	 * (non-Javadoc)
	 * @see javax.sql.DataSource#getConnection()
	 */
	public Connection getConnection() throws SQLException { //spring aop
		if(pool.size()>0){
			final Connection conn = pool.removeFirst();
			System.out.println(conn + "从池里面取出去了!!!");
			return (Connection) Proxy.newProxyInstance(JdbcPool.class.getClassLoader(),conn.getClass().getInterfaces(), new InvocationHandler(){
					//proxy为代理对象 method为要调用的方法 args为方法的参数
				public Object invoke(Object proxy, Method method, Object[] args)
						throws Throwable {
					if(method.getName().equals("close")){
						pool.addFirst(conn);
						System.out.println(conn + "被还到池里面了!!");
						return null;
					}else{
						return method.invoke(conn, args);
					}
				}
			});
			
		}
		throw new RuntimeException("对不起,池里没有资源了!!!");
	}

	public Connection getConnection(String arg0, String arg1)
			throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	public PrintWriter getLogWriter() throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	public int getLoginTimeout() throws SQLException {
		// TODO Auto-generated method stub
		return 0;
	}

	public void setLogWriter(PrintWriter arg0) throws SQLException {
		// TODO Auto-generated method stub
		
	}

	public void setLoginTimeout(int arg0) throws SQLException {
		// TODO Auto-generated method stub
		
	}

	//public Jdbcpool
	
}

 
 
  一般实现第一个就可了,数据库的信息都 是通过配置文件来实现的,
  通过加载配置文件就可以,取得与数据库的连接

 

实现DataSource接口,并实现连接池功能的步骤
 1.在DataSource构造函数中批量创建与数据库的连接,并把创建的连接加入LinkedList对象中
  因为LinkedList 是用链表实现的,对于增删实现起来比较容易
  因为每从池中取出一个连接,都要将这个对象从池不删除,当返回时就要添加回去
  
 2.实现getConnection方法,让getConnection方法每次调用时,
  从LinkedList中取一个Connection返回给用户(即要从池中删除一个对象)
  
 3.当用户使用完Connection,调用Connection.close()方法时,
  Collection对象应保证将自己返回到LinkedList中
  (用户一般都会调用Connection的close方法来关闭连接,从而不能将这个连接返回给池,
  所以这里采用了动态代理技术:赤获取用户关闭连接的操作,当获取到时而不是将其给关闭,
  而是将这个连接(对象)添加到池中)

 

注:

 

** 这里使用动态代理技术返回一个假的Connection,
 当dao调用假connection的任何方法时,该方法体内会调用InvocationHandler.invoke方法
** 在invoke方法体内,发现dao调用的是close方法,则把链接还到池里,
 否则,调用真connection的对应方法。

 

开源的数据库连接池(数据源)

 都提供DataSoruce的实现,即连接池的实现

 DBCP 数据库连接池     C3P0 数据库连接池 
 
 DBCP 是 Apache 软件基金组织下的开源连接池实现,使用DBCP数据源
Commons-dbcp.jar:连接池的实现
Commons-pool.jar:连接池实现的依赖库
它用到了一个配置文件dbcpconfig.properties(放在类路径下)

用BaseDataSourceFactory 对象 装载这个配置文件

private static DataSource dataSource;
	static {
		try {
			InputStream in = JdbcUtil.class.getClassLoader()
					.getResourceAsStream("dbcpconfig.properties");
			Properties prop = new Properties();
			prop.load(in);
			BasicDataSourceFactory factory = new BasicDataSourceFactory();
			dataSource = factory.createDataSource(prop);
		} catch (Exception e) {
			throw new ExceptionInInitializerError(e);
		}
	}
	
	public static Connection getConnection() throws SQLException {
		return dataSource.getConnection();
	}

  

 

在Tomcat 下实现数据库连接池

1.要在META-INF目录下建一个context.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<Context>
  <Resource name="jdbc/dataSource" auth="Container"
            type="javax.sql.DataSource" username="root" password="root"
            driverClassName="com.mysql.jdbc.Driver" 
        url="jdbc:mysql://localhost:3306/jdbc"
            maxActive="8" maxIdle="4"/>
</Context>

 
(这是将数据库连接对象绑定到一个名字中去,要用到时就通过这个名字来找这个对象)JNDI
  2.还要将数据库驱动的JAR复制到Tomcat的LIB目录下,因为Tomcat起动时就会去初始化连接池
   所以就会去找相应的JAR文件,其实这个配置是可以配在Tomcat conf目录下server.xml文件中的
   , 为了不改变它原来的配置,所以配置有那也是一样有效的

  3.取得连接,通过命名空间
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
dataSource = (DataSource)envCtx.lookup("jdbc/dataSource");

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值