自定义--数据库连接池

在hibernate中,session.colse()
1、这只是把session,即连接再放回连接池里,没有关闭连接。
如果不显示的调用session.close(),最终这个连接会因为在一定时间没有使用后给还回连接池,也不会出错,但是在不使用session的那一段时间中,这个session就浪费了,所以在使用完session后要显示的调用session.close()把其还给连接池。
连接池的Connection.close()方法都是使用动态代理模式修改过。

2、调用连接池的close的接口,只是把连接的控制权还给了池子,至于是否关闭要看池子空闲的conn是否达到上限形成浪费,所以conn池的close只是软关闭。真正释放连接资源是pool自行判断并操作的。
session 只是通过conn来操作数据库,它自身是一个会话形式。它和conn只是资源配备的关系。

一、为什么使用数据库连接池

用户每次请求都需要向数据库获得连接,而数据库创建连接通常要消耗相对较大的资源,创建时间也长。假设网站一天10万的访问量,数据库服务器就需要创建10万次连接,极大浪费数据库的资源,并且极易造成数据库服务器内存溢出、宕机。连接池工作原理图:

应用程序一开始就向数据库要了一批连接构成连接池,用户访问 Servlet,Servlet 向 Dao 要数据,此时 Dao 层不是直接向数据库要连接,而是向连接池中拿一个空闲的连接。当 Dao 用完连接以后,将连接还给连接池。

二、编写数据库连接池

1、编写连接池需要实现 java.sql.DataSource 接口。DataSource 接口中定义了两个重载的 getConnection 方法:

Connection.getConnection();

Connection.getConnection(String username, String password);

2、实现 DataSource 接口并实现连接池功能的步骤:

在 DataSource 构造函数中批量创建与数据库的连接,并把创建连接加入到 LinkedList 对象中。实现 getConnection 方法,让 getConnection 方法每次调用时,从 LinkedList 中取一个 Connection 返回给用户。当用户使用完 Connection 对象应保证将连接返回到 LinkedList 中,而不是还给数据库。

在自己编写数据库连接池时,我们要考虑到,从数据库获取连接的时候容易,但是当用户用完连接,调用 connection.close() 方法的时候,会直接将连接交还给数据库而不是再放回连接池中。所以我们要动态的改变 connection 方法。有三种方式可以实现 

(1)写一个 connection 的子类,复写所有方法。但是这种方法有一个问题,因为 connection 对象中封装了太多数据,我们如何将 connection 的数据拷贝到我们当前的子类中呢?这是一个复杂的过程。(2)用装饰模式,装饰模式可以动态的为一个类增加新功能。装饰模式有几个步骤,首先装饰类和被装饰类要有一个共同的父接口,其次装饰类中维护着一个被装饰类的对象,同时在装饰类的构造函数中要将被装饰的对象传进来,目的是赋值。然后我们可以为根据需求增加修改原来的功能。当我们要使用被装饰类的时候,我们给用户返回的是我们装饰后的对象, 从而达到目的。但是装饰模式比较适用于简单类,不适合用于方法多的对象,因为我们有时仅仅需要修改一部分功能,而其它功能还是希望调用被装饰类本身的方法,那么这样我们就必须一个一个方法进行修改,来调用被装饰类的方法,这个工程非常庞大。(3)使用动态代理,动态代理可以实现拦截对对象的直接访问。如果我们想修改某一个方法,只需要在调用对象之前进行判断即可,如果是我们想修改的,我们直接拦截,如果不是我们想要的,我们可以直接交给被代理对象处理。由于动态代理是基于代理对象和被代理对象要有相同接口,所以我们可以基于接口统一调用,运行时以多态的形式表现出来。

  1. public class DataSourcePool {
  2. private static LinkedList<Connection> list =new LinkedList<Connection>();
  3. static {
  4. for (int i = 0; i < 5; i++) {
  5. Connection con = DBHelper.getConnection();
  6. list.add(con);
  7. }
  8. }
  9. public Connection getConnection() throws SQLException {
  10. if (list.size() > 0) {
  11. System.out.println("当前连接池有:" + list.size() + "个连接");
  12. final Connection con = list.removeFirst();
  13. System.out.println("当前连接池有:" + list.size() + "个连接");
  14. return (Connection) Proxy.newProxyInstance(DataSourcePool.class.getClassLoader(), con.getClass().getInterfaces(),new InvocationHandler() {
  15. public Object invoke(Object proxy, Method method, Object[] args)
  16. throws Throwable {
  17. String methodName = method.getName();
  18. if(methodName.equals("close")){
  19. list.add(con);
  20. System.out.println("当前连接池有:" + list.size() + "个连接");
  21. return null;
  22. }else{
  23. return method.invoke(con, args);
  24. }
  25. }
  26. });
  27. }
  28. return null;
  29. }
  30. }
public class DataSourcePool {

	private static LinkedList<Connection> list = new LinkedList<Connection>();

	static {
		for (int i = 0; i < 5; i++) {
			Connection con = DBHelper.getConnection();
			list.add(con);
		}
	}

	public Connection getConnection() throws SQLException {
		if (list.size() > 0) {
			System.out.println("当前连接池有:" + list.size() + "个连接");
			final Connection con = list.removeFirst();
			System.out.println("当前连接池有:" + list.size() + "个连接");
			return (Connection) Proxy.newProxyInstance(DataSourcePool.class.getClassLoader(), con.getClass().getInterfaces(), new InvocationHandler() {

				public Object invoke(Object proxy, Method method, Object[] args)
						throws Throwable {
					String methodName = method.getName();
					if(methodName.equals("close")){
						list.add(con);
						System.out.println("当前连接池有:" + list.size() + "个连接");
						return null;
					}else{
						return method.invoke(con, args);
					}
				}

			});
		}
		return null;
	}
}


3、配置 Tomcat 内置 dbcp 连接池

Tomcat 采用的是 JNDI 容器存放连接的,在服务器启动的时候,会在 JNDI 容器中创建一批连接,应用程序需要连接的时候直接在 JNDI 容器中查找。我们在使用时首先应该初始化 JNDI ,然后获取 Tomcat 中 JNDI 容器,最后在 JNDI 容器中检索连接池。

  1. Context initCtx = new InitialContext();
  2. Context envCtx = (Context) initCtx.lookup("java:comp/env");
  3. DataSource source = (DataSource) envCtx.lookup("jdbc/EmployeeDB"); 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值