利用几种设计模式来实现自定义数据库连接池

利用几种设计模式来实现自定义数据库连接池

自定义数据库连接池

核心API

DataSource 接口概述
javax.sql.DataSource 接口:数据源(数据库连接池)。Java 官方提供的数据库连接池规范(接口)
	* 如果想完成数据库连接池技术,就必须实现 DataSource 接口
	* 核心功能:获取数据库连接对象:Connection getConnection();

实现步骤

① 定义一个类,实现 DataSource 接口。
② 定义一个容器,用于保存多个 Connection 连接对象。
③ 定义静态代码块,通过 JDBC 工具类获取 10 个连接保存到容器中。
④ 重写 getConnection 方法,从容器中获取一个连接并返回。
⑤ 定义 getSize 方法,用于获取容器的大小并返回。

归还数据库连接的方式

① 继承方式
	父类中的一个方法的功能不够完美-->解决方法,创建一个子类来继承,并重写父类中的该方法,以达到目的.
② 装饰者设计模式
	作用:在不改变原有类的情况下增强原有类的功能.
	特点:装饰者以及被装饰者应该是同一个类型.
		如果被装饰者有功能实现那么自己不再重复实现直接使用被装饰者功能.
		装饰者需要做的只是其他额外功能的实现.
③ 适配器设计模式
	对象:
		* 目标接口(我们想要什么类型)
		* 已存在实现
		* 适配(实现目标接口,继承已有实现)
④ 动态代理方式
	动态代理:在不改变目标对象方法的情况下对方法进行增强
	* 组成
		被代理对象:真实的对象
		代理对象:内存中的一个对象
	* 要求
		代理对象必须和被代理对象实现相同的接口
	* 实现
		Proxy.newProxyInstance()
	特点:
		代理出来的对象和原本被代理对象没有任何关系,只不过他们都有相同接口
		如果遇到不想增强的方法那么我们可以利用反射调用被代理对象的方法(这才是产生关联的原因)

1.继承方式

1. 继承方式归还数据库连接的思想。
	* 通过打印连接对象,发现 DriverManager 获取的连接实现类是 JDBC4Connection
	* 那我们就可以自定义一个类,继承 JDBC4Connection 这个类,重写 close() 方法,完成连接对象的归还
2. 继承方式归还数据库连接的实现步骤。
	* 定义一个类,继承 JDBC4Connection 。 
	* 定义 Connection 连接对象和连接池容器对象的成员变量。
	* 通过有参构造方法完成对成员变量的赋值。
	* 重写 close 方法,将连接对象添加到池中。
3. 继承方式归还数据库连接存在的问题。
	* 通过查看 JDBC 工具类获取连接的方法发现:我们虽然自定义了一个子类,完成了归还连接的操作。但是
	DriverManager 获取的还是 JDBC4Connection 这个对象,并不是我们的子类对象,而我们又不能整体
	去修改驱动包中类的功能,所继承这种方式行不通!
继承方式自定义连接池代码
/*
    自定义的连接对象
    1.定义一个类,继承JDBC4Connection
    2.定义Connection连接对象和容器对象的成员变量
    3.通过有参构造方法为成员变量赋值
    4.重写close方法,完成归还连接
 */
public class MyConnection1 extends JDBC4Connection{//1.定义一个类,继承JDBC4Connection
    //2.定义Connection连接对象和容器对象的成员变量
    private Connection con;
    private List<Connection> pool;

    //3.通过有参构造方法为成员变量赋值
    public MyConnection1(String hostToConnectTo, int portToConnectTo, Properties info, String databaseToConnectTo, String url,Connection con,List<Connection> pool) throws SQLException {
        super(hostToConnectTo, portToConnectTo, info, databaseToConnectTo, url);
        this.con = con;
        this.pool = pool;
    }

    //4.重写close方法,完成归还连接
    @Override
    public void close() throws SQLException {
        pool.add(con);
    }
}

2.装饰者设计模式

1. 装饰设计模式归还数据库连接的思想。
	* 我们可以自定义一个类,实现 Connection 接口。这样就具备了和 JDBC4Connection 相同的行为了
	* 重写 close() 方法,完成连接的归还。其余的功能还调用 mysql 驱动包实现类原有的方法即可
2. 装饰设计模式归还数据库连接的实现步骤。
	* 定义一个类,实现 Connection 接口
	* 定义 Connection 连接对象和连接池容器对象的成员变量
	* 通过有参构造方法完成对成员变量的赋值
	* 重写 close() 方法,将连接对象添加到池中
	* 剩余方法,只需要调用 mysql 驱动包的连接对象完成即可
	* 在自定义连接池中,将获取的连接对象通过自定义连接对象进行包装
3. 装饰设计模式归还数据库连接存在的问题。
	* 实现 Connection 接口后,有大量的方法需要在自定义类中进行重写
小案例
public interface KTV {
    void sing();
}
public class BaseKTV implements KTV {
    @Override
    public void sing() {
        //实现基础的唱歌
        System.out.println("唱歌~~");
    }
}
/**
 * 对BaseKTV进行装饰-->灯光
 */
public class LightKTV implements KTV{
    private KTV ktv;

    public LightKTV(KTV ktv){
        this.ktv = ktv;
    }
    public void sing() {
        ktv.sing();
        System.out.println("灯光~~");
    }
}
public class SpecialKTV implements KTV {
    private KTV ktv;
    public SpecialKTV(KTV ktv){
        this.ktv = ktv;
    }
    @Override
    public void sing() {
        ktv.sing();
        System.out.println("嗨皮~~");
    }
}
public class Demo {
    public static void main(String[] args) {
        KTV ktv = new BaseKTV();
        LightKTV lightKTV = new LightKTV(ktv);
        SpecialKTV specialKTV = new SpecialKTV(lightKTV);
        specialKTV.sing();
    }
}
装饰者设计模式自定义连接池代码
/*
    1.定义一个类,实现Connection接口
    2.定义连接对象和连接池容器对象的成员变量
    3.通过有参构造方法为成员变量赋值
    4.重写close方法,完成归还连接
    5.剩余方法,还是调用原有的连接对象中的功能即可
 */
//1.定义一个类,实现Connection接口
public class MyConnection2 implements Connection{

    //2.定义连接对象和连接池容器对象的成员变量
    private Connection con;
    private List<Connection> pool;

    //3.通过有参构造方法为成员变量赋值
    public MyConnection2(Connection con,List<Connection> pool) {
        this.con = con;
        this.pool = pool;
    }

    //4.重写close方法,完成归还连接
    @Override
    public void close() throws SQLException {
        pool.add(con);
    }

    //5.剩余方法,还是调用原有的连接对象中的功能即可

3.适配器模式

1. 适配器设计模式归还数据库连接的思想。
	* 我们可以提供一个适配器类,实现 Connection 接口,将所有方法进行实现(除了close方法)
    * 自定义连接类只需要继承这个适配器类,重写需要改进的 close() 方法即可
2. 适配器设计模式归还数据库连接的实现步骤。
	* 定义一个适配器类,实现 Connection 接口。
	* 定义 Connection 连接对象的成员变量。
	* 通过有参构造方法完成对成员变量的赋值。
	* 重写所有方法(除了 close ),调用mysql驱动包的连接对象完成即可。
	* 定义一个连接类,继承适配器类。
	* 定义 Connection 连接对象和连接池容器对象的成员变量,并通过有参构造进行赋值。
	* 重写 close() 方法,完成归还连接。
	* 在自定义连接池中,将获取的连接对象通过自定义连接对象进行包装。
3. 适配器设计模式归还数据库连接存在的问题。
	* 自定义连接类虽然很简洁了,但适配器类还是我们自己编写的,也比较的麻烦
小案例
public interface Sports {
    void sport();
}
public class Exercises {
    public void doExercises(){
        System.out.println("跑步");
    }
}
public class Shipeiqi extends Exercises implements Sports {
    @Override
    public void sport() {
        doExercises();  //调用父类Exercises的方法
    }
}
public class Master {
    private Sports sport;
    public Master(Sports sport){
        this.sport = sport;
    }
    public void sport(){
        sport.sport();
    }
}
public class Demo {
    public static void main(String[] args) {
        Master master = new Master(new Shipeiqi());
        master.sport();
    }
}
适配器模式自定义连接池代码
/*
    1.定义一个类,继承适配器类
    2.定义连接对象和连接池容器对象的成员变量
    3.通过有参构造为变量赋值
    4.重写close方法,完成归还连接
 */
//1.定义一个类,继承适配器类
public class MyConnection3 extends MyAdapter {

    //2.定义连接对象和连接池容器对象的成员变量
    private Connection con;
    private List<Connection> pool;

    //3.通过有参构造为变量赋值
    public MyConnection3(Connection con,List<Connection> pool) {
        super(con);
        this.con = con;
        this.pool = pool;
    }

    //4.重写close方法,完成归还连接
    @Override
    public void close() {
        pool.add(con);
    }
}
/*
    1.定义一个适配器类。实现Connection接口
    2.定义连接对象的成员变量
    3.通过有参构造为变量赋值
    4.重写所有的抽象方法(除了close)
 */
public abstract class MyAdapter implements Connection {

    //2.定义连接对象的成员变量
    private Connection con;

    //3.通过有参构造为变量赋值
    public MyAdapter(Connection con) {
        this.con = con;
    }
    //4.重写所有的抽象方法(除了close)

4.动态代理

1. 动态代理方式归还数据库连接的思想。
	* 我们可以通过 Proxy 来完成对 Connection 实现类对象的代理
	* 代理过程中判断如果执行的是 close 方法,就将连接归还池中。如果是其他方法则调用连接对象原来的功能即可
2. 动态代理方式归还数据库连接的实现步骤。
	* 定义一个类,实现 DataSource 接口
	* 定义一个容器,用于保存多个Connection连接对象
	* 定义静态代码块,通过 JDBC 工具类获取 10 个连接保存到容器中
	* 重写 getConnection 方法,从容器中获取一个连接
	* 通过 Proxy 代理,如果是 close 方法,就将连接归还池中。如果是其他方法则调用原有功能
	* 定义 getSize 方法,用于获取容器的大小并返回
3. 动态代理方式归还数据库连接存在的问题。
	* 我们自己写的连接池技术不够完善,功能也不够强大
小案例
public interface StudentInterface {
    void study();
    void eat(String name);
}
public class Student implements StudentInterface {
    @Override
    public void study() {
        System.out.println("学java");
    }

    @Override
    public void eat(String name) {
        System.out.println("吃" + name);
    }
}
/*
            要求:在不改动Student类中任何的代码的前提下,通过study方法输出一句话:学成啦!
            类加载器:和被代理对象使用相同的类加载器
            接口类型Class数组:和被代理对象使用相同接口
            代理规则:完成代理增强的功能
         */
public class Demo {
    public static void main(String[] args) {
        Student student = new Student();
        StudentInterface stu = (StudentInterface) Proxy.newProxyInstance(student.getClass().getClassLoader(), student.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if (method.getName().equals("study")){
                    System.out.println("学成啦");
                    return null;
                }else {
                    method.invoke(student,args);
                    return null;
                }
            }
        });
        stu.eat("小面");
        stu.study();
    }
}

自定义连接池代码

public class MyDataSource implements DataSource {
    //1.准备一个容器。用于保存多个数据库连接对象
    private static List<Connection> pool = Collections.synchronizedList(new ArrayList<>());

    //2.定义静态代码块,获取多个连接对象保存到容器中
    static{
        for(int i = 1; i <= 10; i++) {
            Connection con = JDBCUtils.getConnection();
            pool.add(con);
        }
    }

    //4.提供一个获取连接池大小的方法
    public int getSize() {
        return pool.size();
    }

    /*
        动态代理方式
     */
    @Override
    public Connection getConnection() throws SQLException {
        if(pool.size() > 0) {
            Connection con = pool.remove(0);

            Connection proxyCon = (Connection) Proxy.newProxyInstance(con.getClass().getClassLoader(), new Class[]{Connection.class}, new InvocationHandler() {
                /*
                    执行Connection实现类连接对象所有的方法都会经过invoke
                    如果是close方法,归还连接
                    如果不是,直接执行连接对象原有的功能即可
                 */
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    if(method.getName().equals("close")) {
                        //归还连接
                        pool.add(con);
                        return null;
                    }else {
                        return method.invoke(con,args);
                    }
                }
            });

            return proxyCon;
        }else {
            throw new RuntimeException("连接数量已用尽");
        }
    }

    //3.重写getConnection方法,用于返回一个连接对象
    /*@Override
    public Connection getConnection() throws SQLException {
        if(pool.size() > 0) {
            Connection con = pool.remove(0);
            //通过自定义的连接对象 对原有的连接对象进行包装
            //MyConnection2 myCon = new MyConnection2(con,pool);
            MyConnection3 myCon = new MyConnection3(con,pool);
            return myCon;
        }else {
            throw new RuntimeException("连接数量已用尽");
        }
    }*/

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return null;
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值