为什么要有数据库连接池
1.创建Connection的过程是很耗时的
2.一个Connection只能供一个对象使用(所以不能使用单例模式)
3.所以要先创建一堆连接,要一个给你一个,用完了还回来。
什么是代理模式
龙哥博客:代理模式详解
龙哥总结:
从静态代理的使用上来看,我们一般是这么做的。
1,代理类一般要持有一个被代理的对象的引用。
2,对于我们不关心的方法,全部委托给被代理的对象处理。
3,自己处理我们关心的方法。
代理模式
在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。
在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。
介绍
意图:为其他对象提供一种代理以控制对这个对象的访问。
主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。
何时使用:想在访问一个类时做一些控制。
如何解决:增加中间层。
关键代码:实现与被代理类组合。
应用实例: 1、Windows 里面的快捷方式。 2、猪八戒去找高翠兰结果是孙悟空变的,可以这样理解:把高翠兰的外貌抽象出来,高翠兰本人和孙悟空都实现了这个接口,猪八戒访问高翠兰的时候看不出来这个是孙悟空,所以说孙悟空是高翠兰代理类。 3、买火车票不一定在火车站买,也可以去代售点。 4、一张支票或银行存单是账户中资金的代理。支票在市场交易中用来代替现金,并提供对签发人账号上资金的控制。 5、spring aop。
优点: 1、职责清晰。 2、高扩展性。 3、智能化。
缺点: 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
使用场景:按职责来划分,通常有以下使用场景: 1、远程代理。 2、虚拟代理。 3、Copy-on-Write 代理。 4、保护(Protect or Access)代理。 5、Cache代理。 6、防火墙(Firewall)代理。 7、同步化(Synchronization)代理。 8、智能引用(Smart Reference)代理。
注意事项: 1、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。 2、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。
实现
我们将创建一个 Image 接口和实现了 Image 接口的实体类。ProxyImage 是一个代理类,减少 RealImage 对象加载的内存占用。
ProxyPatternDemo,我们的演示类使用 ProxyImage 来获取要加载的 Image 对象,并按照需求进行显示。
数据库连接
原本获得数据库连接需要干的事情
数据库连接池
代码实现
1.创建类ConnectionProxy实现java.sql.Connection接口
2.类ConnectionProxy分别实现基础构造方法,close方法
以及要使用的prepareStatement及createStatement
3.实现DataSource,因为数据库连接池只有一个(所以使用单例模式)
4.DataSource具有的特点其他博客写的很清楚了
ConnectionProxy代码
import java.sql.*;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
public class ConnectionProxy implements Connection {
//设置连接
private Connection connection;
//使用createStatement的方法,如果返回为空,则在后续使用会空指针异常
@Override
public Statement createStatement() throws SQLException {
return this.connection.createStatement();
}
//构造函数,返回连接
public ConnectionProxy() throws SQLException {
this.connection = DataSource.getInstance().getConnection();
}
//同createSatement
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
return this.connection.prepareStatement(sql);
}
//重要的close方法
@Override
public void close() throws SQLException {
DataSource.getInstance().recoveryConnection(connection);
}
}
数据库连接池DataSource
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;
public class DataSource {
private static String url="jdbc:mysql://127.0.0.1:3306/usertest?useUnicode=true&characterEncoding=utf8";
private static String user="root";
private static String password="xxx";
private static int maxConnection=500;
private static int currentConnection=0;
//LinkedList是非线程安全的所以在操纵LinkedList的时候需要加锁
//需要序列化和反序列化实现单例
private static LinkedList<Connection> connectionList=new LinkedList<Connection>();
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private static Connection createNewConnection() throws SQLException {
return DriverManager.getConnection(url,user,password);
}
private DataSource(){
//类初始化不需要加锁
if (connectionList==null||connectionList.size()==0){
for (int i = 0; i < 10; i++) {
try {
connectionList.add(createNewConnection());
} catch (SQLException e) {
e.printStackTrace();
}
currentConnection++;
System.out.println("当前共有连接"+currentConnection);
}
}
}
public Connection getConnection() throws SQLException {
synchronized (DataSource.class){
if (connectionList.size()>0){
System.out.println("有连接可以,从LinkedList中移除一个连接");
return connectionList.remove();
}
if (currentConnection<maxConnection){
try {
return createNewConnection();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
throw new SQLException("无连接可用");
}
public void recoveryConnection(Connection connection){
System.out.println("DataSource获得恢复连接");
synchronized (DataSource.class) {
connectionList.add(connection);
}
}
public static DataSource getInstance(){
return DataSourceInstance.dataSource;
}
private static class DataSourceInstance{
//这里需要写成单例模式 这里使用内部静态类实现单例模式
private static DataSource dataSource = new DataSource();
}
}
写在最后
数据库连接池的实现使用静态代理即可,推荐大家搭配我前面的博客数据库的操作封装使用,相当于自己写了框架Mybatis的感觉,特别爽。