阅读文本大概需要 8 分钟。
度过了一个轻松的周末,让我们收拾好行囊,继续数据库航行之路 。
先简单回顾一下上次我们提到的
JDBCUtil 工具类
,通过抽取的 getConnection 和 release 方法实现,我们现在可以方便的获取以及释放数据库连接资源了。
可是 这还够,还不够…
新的问题:
创建一个 Connection,发出一个查询,处理完 ResultSet 后,立刻就把Connection 给关掉了。这在我们简单的单用户 CS 程序,是没有问题的。可现在的 Java 程序往往是 BS 的 Web 应用,需要处理的是大量来自不同用户的请求。
用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。
假设网站一天10万访问量,数据库服务器就需要创建关闭10万次连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出、拓机。
那么最好的做法是,准备出一个空间,此空间里专门保存着数据库连接。以后用户要用数据库操作的时候,不用再重新加载驱动、连接数据库之类的,而直接从此空间中获取 Connection 连接。关闭的时候,直接把连接放回到此空间之中。
这个空间就可以称为连接池,而连接池存在的意义,就是提高获取链接的效率。
模拟连接池
准备一个存放对象的池子(容器)
最开始初始化一些连接到池子中
获取已有的连接
用完后换回池中
简单实现:
使用连接池:
标准的数据源
现在我们,有了保存所有的数据库连接的连接池,但是如果要想真正有效的使用数据库连接池空间的话,还有一些问题要考虑
1、 如果没有任何一个用户使用连接,那么那么应该维持一定数量的连接,等待用户使用。
2、 如果连接已经满了,则必须打开新的连接,供更多用户使用。
3、 如果一个服务器就只能有60个连接,那么如果有第61个人过来呢?应该等待其他用户释放连接
4、 如果一个用户等待时间太长了,则应该告诉用户,操作是失败的。
如果直接用程序实现以上功能 会比较麻烦,所以 java 为数据库连接池提供了公共的接口:
javax.sql.DataSource
要求各个厂商的连接池必须实现该接口,这样应用程序就能方便的切换不同厂商的连接池。
每一个连接通过 DataSource 获取,并规定清楚了:
初始连接数
最小空闲连接数
创建连接的最小增量
最大空闲连接数
最大连接数
最长等待时间
… …
DataSource 被绑定在了JNDI 上(为每一个DataSource提供一个名字)客户端通过名称找到在 JNDI 上绑定的DataSource,再由DataSource找到一个连接。
还有一个小问题
从池中获取一个链接后,用户用完自觉的调用 conn.close() 方法。应该达到的效果:不要关闭,而应该还回池中。
解决方案:
1、静态代理
自己编写一个类,实现 Connection 接口。对于不需要改写的方法,调用被装饰对象的。( 装饰者 l 默认适配器)。对于要改写的 close() 方法,改写即可。
2、动态代理
基于接口的动态代理:被代理对象的类,实现了至少一个接口
通过 Proxy 类反射,重新提供 close 方法。
ClassLoadder loader:类加载器。固定写法:和被代理人用相同的类加载器即可。
Interface[] interfaces:代理对象要实现的接口。固定写法:和被代理人相同即可。
InvocationHandler h:接口。如何代理。策略设计模式。
今日总结:
连接池 是用来管理 Connection 以便于 Connection 能够复用。
有了连接池,我们就不用每次都来创建 Connection,而是通过连接池来获取 Connection 对象。
当使用完 Connection 之后,调用 close() 方法,也不会真正的关闭连接,而是将 Connection ”归还”给连接池。
连接池就能够再次利用这个 Connection. 而无需重新创建,从而节省了系统资源、优化了性能。
领取专属 10元无门槛券
私享最新 技术干货