代理模式实例-数据库连接池的实现

为什么要有数据库连接池

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 对象,并按照需求进行显示。

代理模式的 UML 图

数据库连接

原本获得数据库连接需要干的事情
这里写图片描述

数据库连接池

这里写图片描述

代码实现

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的感觉,特别爽。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值