帶泛型的BaseDAO封裝與使用

什么是DAO?

  • DAOData Access Object訪問數(shù)據(jù)信息的類和接口,包括了對數(shù)據(jù)的CRUD,而不包含任何業(yè)務(wù)相關(guān)的信息迹鹅。
  • 作用:為了實(shí)現(xiàn)功能的模塊化担孔,更有利于代碼的維護(hù)和升級江锨。

在實(shí)際開發(fā)中,DAO層主要做的是數(shù)據(jù)持久層的工作糕篇,簡單說就是和數(shù)據(jù)庫打交道的啄育。針對每張表都會創(chuàng)建相應(yīng)的xxxDAO類來實(shí)現(xiàn),由于每張表都會有很多相似的CRUD操作拌消,這些都是重復(fù)代碼挑豌,這時就可以對這些代碼進(jìn)行抽取,封裝成BaseDAO拼坎,之后使用浮毯,只需繼承BaseDAO,即可使用通用的CRUD操作泰鸡。

BaseDAO的封裝與使用

BaseDAO的封裝:

/**
 * DAO:data(base) access object
 * 封裝了針對于數(shù)據(jù)表的通用的操作
 */
public abstract class BaseDAO<T> {

    // 定義一個變量來接收泛型的類型
    private Class<T> clazz = null;

//    public BaseDAO(){
//
//    }

    // 這個代碼塊中的內(nèi)容也可以放在上面的構(gòu)造函數(shù)中
    {
        // 獲取父類的類型债蓝,這里的this是子類對象
        // getGenericSuperclass():用來獲取當(dāng)前類的父類的類型,如果是帶泛型的盛龄,
        // 則返回的type對象必須準(zhǔn)確反映泛型參數(shù)的實(shí)際類型
        Type genericSuperclass = this.getClass().getGenericSuperclass();
        // ParameterizedType:表示參數(shù)化類型
        ParameterizedType paramType = (ParameterizedType) genericSuperclass;
        // 獲取父類的泛型參數(shù)
        Type[] typeArguments = paramType.getActualTypeArguments();
        // 獲取第一個泛型參數(shù)饰迹,這里我們只用了一個泛型
        clazz = (Class<T>) typeArguments[0];
    }

    //通用的增刪改操作 ---- version 2.0
    public int update(Connection conn, String sql, Object ...args) {

        PreparedStatement ps = null;
        try {
            // 1. 預(yù)編譯sql語句,返回PreparedStatement的實(shí)例
            ps = conn.prepareStatement(sql);
            // 2. 填充占位符
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }
            // 3. 執(zhí)行
            return ps.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 4. 關(guān)閉資源
            JDBCUtils.closeResouse(null, ps);
        }

        return 0;
    }

    // 不同表的通用查詢操作余舶,返回表中的一條記錄(version 2.0 考慮上事務(wù))
    public T getBean(Connection conn, String sql, Object... args) {

        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            ps = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }

            rs = ps.executeQuery();
            ResultSetMetaData rsmd = rs.getMetaData();
            int columnCount = rsmd.getColumnCount();
            if (rs.next()) {
                T t = clazz.newInstance();
                for (int i = 0; i < columnCount; i++) {
                    Object columnValue = rs.getObject(i + 1);
                    String columnLabel = rsmd.getColumnLabel(i + 1);
                    Field field = clazz.getDeclaredField(columnLabel);
                    field.setAccessible(true);
                    field.set(t, columnValue);
                }
                return t;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResouse(null, ps, rs);
        }

        return null;
    }

    // 不同表的通用查詢操作啊鸭,返回表中的多條記錄構(gòu)成的集合 version2.0 考慮事務(wù)
    public List<T> getBeanForList(Connection conn, String sql, Object... args) {

        List<T> list = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            ps = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }
            rs = ps.executeQuery();
            ResultSetMetaData rsmd = rs.getMetaData();
            int columnCount = rsmd.getColumnCount();
            list = new ArrayList<>();
            while (rs.next()) {
                T t = clazz.newInstance();
                for (int i = 0; i < columnCount; i++) {
                    Object columnValue = rs.getObject(i + 1);
                    String columnLabel = rsmd.getColumnLabel(i + 1);
                    Field field = clazz.getDeclaredField(columnLabel);
                    field.setAccessible(true);
                    field.set(t, columnValue);
                }
                list.add(t);
            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResouse(null, ps, rs);
        }
        return null;
    }

    /**
     * 用于查詢特殊值的通用方法,例如select count(*)...這樣的sql語句
     */
    public <E> E getValue(Connection conn, String sql, Object... args) {

        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            ps = conn.prepareStatement(sql);

            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }

            rs = ps.executeQuery();
            if (rs.next()) {
                return (E) rs.getObject(1);
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JDBCUtils.closeResouse(null, ps, rs);
        }
        return null;
    }
}

主要的難點(diǎn)在于怎么獲得泛型參數(shù)的真實(shí)類型匿值。

CustomerDAO接口:

/**
 * @Description 此接口用于規(guī)范針對于customers表的常用操作
 */
public interface CustomerDAO {
    /**
     * 將Customer對象添加到數(shù)據(jù)庫中
     * @param conn
     * @param cust
     */
    void insert(Connection conn, Customer cust);

    /**
     * 針對指定的id赠制,刪除表中的一條記錄
     * @param conn
     * @param id
     */
    void deleteById(Connection conn, int id);

    /**
     * 針對內(nèi)存中過的cust對象,去修改數(shù)據(jù)表中指定的記錄
     * @param conn
     * @param cust
     */
    void update(Connection conn, Customer cust);

    /**
     * 針對指定的id查詢得到對應(yīng)的Customer對象
     * @param conn
     * @param id
     */
    Customer getCustomerById(Connection conn, int id);

    /**
     * 查詢表中的所有記錄構(gòu)成的集合
     * @param conn
     * @return
     */
    List<Customer> getAll(Connection conn);

    /**
     * 返回?cái)?shù)據(jù)表中的條目數(shù)
     * @param conn
     * @return
     */
    Long getCount(Connection conn);

    /**
     * 返回?cái)?shù)據(jù)表中最大的生日
     * @param conn
     * @return
     */
    Date getMaxBirth(Connection conn);
}

CustomerDAOImpl

public class CustomerDAOImpl extends BaseDAO<Customer> implements CustomerDAO {
    @Override
    public void insert(Connection conn, Customer cust) {
        String sql = "insert into customers(name, email, birth) values(?,?,?)";
        update(conn, sql, cust.getName(), cust.getEmail(), cust.getBirth());
    }

    @Override
    public void deleteById(Connection conn, int id) {
        String sql = "delete from customers where id = ?";
        update(conn, sql, id);
    }

    @Override
    public void update(Connection conn, Customer cust) {
        String sql = "update customers set name = ?, email = ?, birth = ? where id = ?";
        update(conn, sql, cust.getName(), cust.getEmail(), cust.getBirth(), cust.getId());
    }

    @Override
    public Customer getCustomerById(Connection conn, int id) {
        String sql = "select id, name, email, birth from customers where id = ?";
        Customer customer = getBean(conn, sql, id);
        return customer;
    }

    @Override
    public List<Customer> getAll(Connection conn) {
        String sql = "select id, name, email, birth from customers";

        List<Customer> list = getBeanForList(conn, sql);

        return list;
    }

    @Override
    public Long getCount(Connection conn) {
        String sql = "select count(*) from customers";

        return getValue(conn, sql);
    }

    @Override
    public Date getMaxBirth(Connection conn) {
        String sql = "select max(birth) from customers";

        return getValue(conn, sql);
    }
}

Customer類:

// get挟憔、set钟些,有參和無參構(gòu)造以及toString方法自行補(bǔ)齊
public class Customer {

    private int id;
    private String name;
    private String email;
    private Date birth;

測試代碼:

class CustomerDAOImplTest {

    private CustomerDAOImpl dao = new CustomerDAOImpl();

    @org.junit.jupiter.api.Test
    void insert() {
        Connection conn = null;
        try {
            conn = JDBCUtils.getConnection();
            Customer customer = new Customer(1, "馮寶寶", "bb@163.com", new Date(464234678L));
            dao.insert(conn, customer);
            System.out.println("添加成功");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResouse(conn, null);
        }

    }

    @org.junit.jupiter.api.Test
    void deleteById() {
        Connection conn = null;
        try {
            conn = JDBCUtils.getConnection();
            dao.deleteById(conn, 19);
            System.out.println("刪除成功");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResouse(conn, null);
        }
    }

    @org.junit.jupiter.api.Test
    void update() {
        Connection conn = null;
        try {
            conn = JDBCUtils.getConnection();
            Customer customer = new Customer(5, "哪吒", "nezha@163.com", new Date(165461346L));
            dao.update(conn, customer);
            System.out.println("修改成功");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResouse(conn, null);
        }
    }

    @org.junit.jupiter.api.Test
    void getCustomerById() {
        Connection conn = null;
        try {
            conn = JDBCUtils.getConnection();
            Customer customer = dao.getCustomerById(conn, 5);

            System.out.println(customer);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResouse(conn, null);
        }
    }

    @org.junit.jupiter.api.Test
    void getAll() {
        Connection conn = null;
        try {
            conn = JDBCUtils.getConnection();
            List<Customer> list = dao.getAll(conn);
            list.forEach(System.out::println);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResouse(conn, null);
        }
    }

    @org.junit.jupiter.api.Test
    void getCount() {
        Connection conn = null;
        try {
            conn = JDBCUtils.getConnection();
            Long count = dao.getCount(conn);
            System.out.println(count);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResouse(conn, null);
        }
    }

    @org.junit.jupiter.api.Test
    void getMaxBirth() {
        Connection conn = null;
        try {
            conn = JDBCUtils.getConnection();
            Date maxBirth = dao.getMaxBirth(conn);
            System.out.println(maxBirth);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResouse(conn, null);
        }
    }
}

如果對你有幫助,點(diǎn)個贊唄绊谭,關(guān)注公眾號程序員汪汪政恍,一起探討更多Java問題!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末达传,一起剝皮案震驚了整個濱河市篙耗,隨后出現(xiàn)的幾起案子迫筑,更是在濱河造成了極大的恐慌,老刑警劉巖宗弯,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件脯燃,死亡現(xiàn)場離奇詭異,居然都是意外死亡蒙保,警方通過查閱死者的電腦和手機(jī)曲伊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來追他,“玉大人,你說我怎么就攤上這事岛蚤∫乩辏” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵涤妒,是天一觀的道長单雾。 經(jīng)常有香客問我,道長她紫,這世上最難降的妖魔是什么硅堆? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮贿讹,結(jié)果婚禮上渐逃,老公的妹妹穿的比我還像新娘。我一直安慰自己民褂,他們只是感情好茄菊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著赊堪,像睡著了一般面殖。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上哭廉,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天脊僚,我揣著相機(jī)與錄音,去河邊找鬼遵绰。 笑死辽幌,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的街立。 我是一名探鬼主播舶衬,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼赎离!你這毒婦竟也來了逛犹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎虽画,沒想到半個月后舞蔽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡码撰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年渗柿,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片脖岛。...
    茶點(diǎn)故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡朵栖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出柴梆,到底是詐尸還是另有隱情陨溅,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布绍在,位于F島的核電站门扇,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏偿渡。R本人自食惡果不足惜臼寄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望溜宽。 院中可真熱鬧吉拳,春花似錦、人聲如沸适揉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽涡扼。三九已至稼跳,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間吃沪,已是汗流浹背汤善。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留票彪,地道東北人红淡。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像降铸,于是被迫代替她去往敵國和親在旱。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容