JDBC常用方法封裝

鴻鈞道友發表於2020-12-13

常用方法封裝

學過JDBC後,會時常會用增刪改查的方法,而一而再,再而三的重複的寫會使程式碼出現冗餘並且不太美觀,因此將會需要使用的方法封裝起來則成了上上之選,所以,我決定將會需要用到的方法進行封裝,使用起來也會方便很多.

1.可以將JDBC中最常用的三個步驟進行封裝:

  • 載入驅動
  • 獲取連線
  • 獲取執行sql語句的物件
  • 執行
  • 處理結果
  • 關閉資源
public class DBUtils {

    /**驅動類路徑*/
    private static final String DRIVER_CLASS = "com.mysql.jdbc.Driver";
    /**URL地址*/
    private static final String URL = "jdbc:mysql://localhost:3306/資料庫名";
    /**登入資料庫伺服器的賬號*/
    private static final String USER = "使用者名稱";
    /**登入資料庫伺服器的密碼*/
    private static final String PASSWORD = "密碼";

    static{
        try {
            // 1.載入驅動
            Class.forName(DRIVER_CLASS);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 返回資料庫連線物件
     * @return
     */
    public static Connection getConn(){
        try {
            return DriverManager.getConnection(URL,USER,PASSWORD);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 關閉資源
     * @param rs    結果集
     * @param stat  處理SQL的執行物件
     * @param conn  資料庫連線
     */
    public static void close(ResultSet rs, Statement stat,Connection conn){
        //ctrl+alt+t
        try {
            if(rs != null){
                rs.close();
            }
            if(stat != null){
                stat.close();
            }
            if(conn != null){
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    
}

2.對查詢會需要的分頁查詢:

public class Query02 {

    /**
     *
     * @param offset  查詢偏移量(起始查詢的資料位置)(使用者選擇頁數-1)*每頁顯示資料條數即可獲得        							 				
     * @param limit   查詢結果集限制行(每頁最大顯示資料行)
     */
    public static List<User> queryLimit(int offset, int limit) throws SQLException {
        List<User> list = new ArrayList<>();
        //引數1:開始查詢的位置
        //引數2:查詢的資料條數
        String sql = "select * from user limit ?,?";
        Connection conn = DBUtils.getConn();
        PreparedStatement ps = conn.prepareStatement(sql);
        ps.setInt(1,offset);
        ps.setInt(2,limit);
        ResultSet rs = ps.executeQuery();
        while (rs.next()) {
        	//資料表的一條的資料
            int id = rs.getInt("id");
            String username = rs.getString("username");
            String password = rs.getString("password");
            String nickname = rs.getString("nickname");
            int status = rs.getInt("status");
            int gid = rs.getInt("gid");
            //每一次迴圈,產生一個r物件
            list.add(new User(id,username,password,status,nickname,gid));
        }
        DBUtils.close(rs,ps,conn);
        return list;
    }

    public static void main(String[] args) throws SQLException {
        //真分頁(select * from XXX limit ?,?) :物理分頁,從資料庫查詢多少條顯示多少條
        //假分頁(select * from XXX):邏輯分頁,一次性將資料全部從資料庫查詢出來,然後再記憶體中通過subList擷取部分顯示

        //當前頁碼
        int pageNow = 1;
        //每頁資料條數
        int pageSize = 10;
        //計算起始查詢位置
        int offset = (pageNow - 1) * pageSize;
        List<User> users = queryLimit(offset, pageSize);
        //遍歷輸出結果
        users.forEach(u-> System.out.println(u));
    }
}

3.對最常用的增刪改查進行封裝:

/**
     * 封裝通用的更新操作(即通過該方法實現對於任意資料表的insert,update,delete操作)
     * @param sql       需要被執行sql語句
     * @param params    執行sql語句時需要傳遞進去引數
     * @return          執行結果
     */
public static boolean exeUpdate(String sql,Object... params){
    Connection conn = getConn();
    PreparedStatement ps = null;
    try {
        ps = conn.prepareStatement(sql);
        //當傳入的引數不為null時執行預處理
        if(Objects.nonNull(params)){
            for (int i = 0; i < params.length; i++) {
                ps.setObject(i + 1,params[i]);
            }
        }
        //執行更新
        return ps.executeUpdate() > 0;
    } catch (SQLException e) {
        e.printStackTrace();
    } finally{
        DBUtils.close(null,ps,conn);
    }
    return false;
}

4.對不同的查詢要求的方法進行不同的封裝:

/**封裝查詢一個記錄*/
    public  static Object queryOne(String sql, Callback call, Object... params){
        Connection conn = getconn();
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            ps = conn.prepareStatement(sql);
            if(Objects.nonNull(params)){
                for (int i = 0; i < params.length; i++) {
                    ps.setObject(i+1,params[i]);
                    rs = ps.executeQuery();
                    //將結果集轉換為Object並返回
                    return call.toObject(rs);
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            Dbutils.close(rs,ps,conn);
        }
        return  null;
    }

    /**
     * 封裝查詢多條記錄
     * @param sql
     * @param call
     * @param params
     * @return
     */
    public  static List queryList(String sql, Callback call, Object... params){
        Connection conn = getconn();
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            ps = conn.prepareStatement(sql);
            if(Objects.nonNull(params)){
                for (int i = 0; i < params.length; i++) {
                    ps.setObject(i+1,params[i]);
                }

                rs = ps.executeQuery();
                //將結果集轉換為Object並返回
                return call.toList(rs);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            Dbutils.close(rs,ps,conn);
        }
        return  null;
    }

    //內部介面
    public interface Callback{
        //回撥函式(鉤子函式)

        /**
         * 將結果集轉換為object物件,為查詢單條資料準備
         * @param rs
         * @return
         */
        default Object toObject(ResultSet rs){
            return null;
        }

        /**
         * 可以將結果集轉換為list物件,為查詢多條資料準備
         * @param rs
         * @return
         */
        default List toList(ResultSet rs){
            return null;
        }

    }

將這些方法進行封裝後我們寫程式碼時也能夠更加輕鬆並且高效,同時程式碼是可以學習的越深而優化的越好,我這個還只是優化1.0,後面還會有更好的辦法來解決這些問題,生命不息,優化不止.

相關文章