JBDCUtils工具类+数据库连接池+装饰者模式对数据库连接的封装实现详解

1. JBDCUtils工具类+数据库连接池+装饰者模式对数据库连接的封装实现详解

1.1. JBDCUtils工具类的意义

  1. JBDCUtils工具类的实现主要是用来封装数据库的连接,最初的数据库连接是有一个类实现,但是这个类里面包含数据库连接url、Driver、用户名、密码。这个类简单直接,但是不利于移植,因为url、Driver都被写死了,如果要换个数据库,还要重新修改类。不符合java的"高内聚,低耦合"的思想。
  2. 封装了数据库连接,通过读取配置文件properties的方式获取数据库连接,符合MVC架构的分层思想。有利于软件开发。

1.2. JBDCUtils都包含哪些方法

  1. 一个静态代码块,用于读取配置文件,加载类时连接数据库。
  2. 给其他类获取连接数据库的方法。
  3. 用于释放连接,释放结果集,关闭接口的方法。

代码:

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import java.util.ResourceBundle;

/**
 * 提供获取连接和释放资源的 方法
 * 
 */
public class JDBCUtils_V3 {
    private static String driver;
    private static String url;
    private static String username;
    private static String password;

    /**
     * 静态代码块加载配置文件信息
     */
    static {
        try {
            // 1.通过当前类获取类加载器
            ClassLoader classLoader = JDBCUtils_V3.class.getClassLoader();
            // 2.通过类加载器的方法获得一个输入流
            InputStream is = classLoader.getResourceAsStream("db.properties");
            // 3.创建一个properties对象
            Properties props = new Properties();
            // 4.加载输入流
            props.load(is);
            // 5.获取相关参数的值
            driver = props.getProperty("driver");
            url = props.getProperty("url");
            username = props.getProperty("username");
            password = props.getProperty("password");
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 获取连接方法
     * @return
     */
    public static Connection getConnection() {
        Connection conn = null;
        try {
            Class.forName(driver);
            conn = DriverManager.getConnection(url, username, password);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return conn;
    }

    public static void release(Connection conn, PreparedStatement pstmt, ResultSet rs) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (pstmt != null) {
            try {
                pstmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }
}

1.3. JDBC连接池的使用意义

由于数据库的连接关闭极大的消耗了资源,浪费cpu时间。为了降低这种资源的浪费,因此创建了连接池连接数据库的方法。当你需要数据库连接时,可以从连接池里取出一个连接,当你关闭连接时也并不是真正的关闭了连接,而是将连接释放到了连接池中,这样就减少了资源的浪费。

java提供了连接池的接口:import javax.sql.DataSource;我们需要根据自身需要去实现这个类,也就是说根据自己的情况创建一个实现这个连接池接口的类,这个类称为连接池。。

1.4. 连接池中有哪些方法

  1. 创建一个容器,用于存储连接数据库的连接对象,其实就是一个实体类entity。
  2. 一个静态代码块,类加载时就运行。主要是为了实现n(连接池容量)个连接对象,并将这些连接放到容器里面。
  3. 重写getConnection()方法,用于实现从连接池中获取一个连接。
  4. 重写backConnection()方法,用于将不用的连接归还到连接池中。
public class MyDataSource implements DataSource{
    //1.创建一个容器用于存储Connection对象。
    private static LinkedList<Connection> pool=new LinkedList<Connection>();
    //2.创建5个连接放到池子里面去。
    static {
        for(int i=0;i<5;i++) {
            Connection conn=JDBCUtils_V3.getConnection();
            pool.add(conn);
        }
    }
    @Override
    public Connection getConnection() throws SQLException {
        Connection conn=null;
        //使用前先判断
        if(pool.size()==0) {
            //4.池子里面没有我们再创建一些。
            for(int i=0;i<5;i++) {
                conn=JDBCUtils_V3.getConnection();
                pool.add(conn);
            }
        }
        //5.从池子里面获取一个连接对象
        conn=pool.remove(0);
        return conn;
    }
    /**
     * 归还连接对象到池子。
     * 
     */
    public void backConnection(Connection conn) {
        pool.add(conn);
    }
}

1.5. 自定义连接池代码改进(装饰者模式的应用)

1.5.1. 为什么要改进?

如果不改进,例如Connection 对象conn,当我们调用该对象的close()方法时,就会关闭连接,而不是回到连接池中,为了实现万一用户调用了close()方法,让连接重新回到连接池中这个功能,需要对自定义连接池代码进行改进。改进的方法采用装饰者模式。装饰者模式专门实现方法的增强。不过必须有接口

1.5.2. 装饰者模式解决问题:

  1. 装饰者模式主要用于扩展对象的功能,是继承关系的一种替代,装饰者模式可以在不产生大量子类的情况下,将对象的功能加以扩展。

  2. 继承会产生大量子类,而且代码会有冗余。

031201.png

如上图:如果没有装饰者模式会先创建手抓饼、肉夹馍两个类。然后再分别创建4个子类分别是手抓饼+煎蛋类,手抓饼+火腿片类等等,8个子类才能满足客户需求。如果配料更多,还要更多子类。

如果采用装饰者模式只需要生成四个子类就行了。

1.5.3. 本人对装饰者模式的理解:

  1. 装饰者模式分为抽象构件角色,Component,具体构件角色Concrete Component,装饰角色Decorator,具体装饰角色Concrete Component。

    抽象构件角色 (Component):一般是接口或者抽象类,包含了一些方法。

    具体构件角色(Concrete Component):是Component角色的实现类。用于实现其方法。

    装饰者角色(Decorator):是一个抽象类,是具体装饰角色的抽象类,这个类很重要,也是装饰者模式的意义所在,这个抽象类实现了Component角色,并且里面 必须有一个Component角色的引用。因为有了这个引用就可以通过多态的方式调用其子类(实现类)的方法。进而起到装饰作用。

    具体装饰者角色(Concrete Component):用于实现Decorator角色,这里面也必须有Component角色引用,应该说是:先在子类里面写,然后再往父类写,因为你对象实例化时是实例化的子类对象。通过引用实例化了对象。

  2. 我认为,装饰者模式是为了在不修改已有实现类的情况下或者减少继承子类数目冗余的情况下功能的一种扩展,在构造装饰者模式时,首先要分清角色,先将具体装饰者角色抽象起来,形成一个抽象类即:装饰者角色Decrator。再将Decrator继承抽象构件角色,Decrator这样就形成了和构件角色同一等级的情况。如下图:

    031202.png
  1. 装饰者类的使用:

    首先new 具体构件类,会生成一个具体构件类对象。

    其次再new具体装饰者类,并将具体构件对象传递过去,这样就形成了一个多态,通过多态调用具体装饰者的子类方法,就实现了功能的扩充。(具体装饰类扩充了功能)。

1.5.4. 对今天的jdbc+连接池的应用:

前面提到需要对连接对象的close()方法进行扩充、完善,用于达到调用close()方法时将连接返回到连接池。

  1. 分析角色:

    抽象构件角色:Connection这是一个接口类 或者说是AutoCloseable接口。

    具体构件角色:DriverManager.getConnection();这个方法实则是实现了Connection接口。Decrator装饰者角色:由于类不多,这个没有直接是具体装饰者类,

    具体装饰者类:我们需要创建一个这种角色,并且实现Connection接口,此外该类里面必须含有Connection 引用。

    这是一个只包含三个角色的三角关系因为具体装饰者类只有一个类没有必要再抽象出来一个抽象类,直接继承抽象构件类就可以了。

  2. 代码分析:

    首先是实现连接池接口的连接池类,这里面调用了Connection接口,并通过JDBCUtils_v3.getConnection()实现了该接口。并传递Connection对象到了MyConnection具体装饰者类的构造器中。

    public class MyDataSource1 implements DataSource{
     //1.创建1个容器用于存储Connection对象
     private static LinkedList<Connection> pool = new LinkedList<Connection>();
     
     //2.创建5个连接放到容器中去
     static{
         for (int i = 0; i < 5; i++) {
             Connection conn = JDBCUtils_V3.getConnection();
             //放入池子中connection对象已经经过改造了
             MyConnection myconn = new MyConnection(conn, pool);
             pool.add(myconn);
         }
     }
     
     /**
      * 重写获取连接的方法
      */
     @Override
     public Connection getConnection() throws SQLException {
         Connection conn = null;
         //3.使用前先判断
         if(pool.size()==0){
             //4.池子里面没有,我们再创建一些
             for (int i = 0; i < 5; i++) {
                 conn = JDBCUtils_V3.getConnection();
                 //放入池子中connection对象已经经过改造了
                 MyConnection myconn = new MyConnection(conn, pool);
                 pool.add(myconn);
             }
         }
         //5.从池子里面获取一个连接对象Connection
         conn = pool.remove(0);
         return conn;
     }
    
     /**
      * 归还连接对象到连接池中去
      */
     public void backConnection(Connection conn){
         pool.add(conn);
     }
    }
    

    这是MyConnection具体装饰者类。

    //1.实现同一个接口Connection
    public class MyConnection implements Connection {
     //3.定义一个变量
     private Connection conn;
     
     private LinkedList<Connection> pool;
     
     // 2.编写一个构造方法(参数使用了面相对象的多态特性)
     public MyConnection(Connection conn,LinkedList<Connection> pool) {
         this.conn=conn;
         this.pool=pool;
     }
     
     //4.书写需要增强的方法
     @Override
     public void close() throws SQLException {
         pool.add(conn);
     }
    
     /**
      * 此方法必须覆盖!否则会出现空指针异常!!!
      */
     @Override
     public PreparedStatement prepareStatement(String sql) throws SQLException       {
         return conn.prepareStatement(sql);
     }
    }
    

1.5.5. 参考链接:

  1. 博客连接1
  2. 博客连接2
  3. 博客连接3
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,706评论 4 366
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,002评论 1 301
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,462评论 0 250
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,375评论 0 216
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,763评论 3 294
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,849评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,033评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,768评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,490评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,734评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,204评论 1 264
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,566评论 3 260
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,227评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,137评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,934评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,926评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,774评论 2 274

推荐阅读更多精彩内容