JDBC | JDBC編碼步驟及各個對象詳解

目錄

 

1.JDBC的概念

2.JDBC編碼步驟

3.詳解各個對象

1)DriverManager:驅動管理對象

2)Connection:數據庫連接對象

3)Statement:執行sql的對象

4)ResultSet:結果集對象,封裝返回結果的

5)reperPreparedStatement:也是執行sql對象,但比Statement功能強大


1.JDBC的概念

        JDBC=Java DataBase Connectivity,使用同樣的Java代碼操作不同的數據庫。

        本質:是官方定義的一套操作關係型數據庫的規則,即接口。各個數據庫廠商去實現這套接口,提供數據庫驅動的jar包。我們可以使用這套接口(JDBC)編程,真正執行的代碼是驅動jar包中的實現類。

2.JDBC編碼步驟

  1. 導入驅動jar包  (此處相關jar包見https://blog.csdn.net/weixin_44187963/article/details/104864821
  2. 編寫代碼註冊驅動
  3. 獲取數據庫的連接對象 connection
  4. 定義SQL語句
  5. 獲取SQL語句對象 statement
  6. 執行SQL,接收返回結果
  7. 處理返回結果
  8. 釋放資源
public class JdbcDome01 {
    public static void main(String[] args) throws Exception {
        //1.導入JAR包
        //2.註冊驅動,在mysql5版本之後可以省略這個步驟,因爲jar包裏配置,系統回會自動註冊驅動
        Class.forName("com.mysql.cj.jdbc.Driver");
        //3.獲取數據庫的連接對象
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/TestDB?serverTimezone=UTC","root","123456");
        //4.定義sql語句
        String sql = "update person set id = 161004 where id = 4";
        //5.獲取執行sql的對象  statement
        Statement stat = conn.createStatement();
        //6.執行sql
        int info = stat.executeUpdate(sql);
        //7.處理結果
        System.out.println(info);
        //8.釋放資源
        conn.close();
        stat.close();
    }
}

當然,這塊只是梳理流程,並沒有去抓取異常。而且關閉資源的代碼理應在異常處理的finally塊中,纔會不論前面是否異常最終都會執行到finally,這樣以免產生內存的泄露。所以代碼可以改爲:

public class JdbcDome03 {
    public static void main(String[] args) {
        Connection con = null;
        Statement sta = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            con = DriverManager.getConnection("jdbc:mysql://localhost:3306/TestDB?serverTimezone=UTC","root","123456");
            String sql = "update person set id = 161005 where id = 5";//修改表sql
            sta = con.createStatement();
            int count = sta.executeUpdate(sql);
            if(count > 1){
                System.out.println("修改成功");
            }else{
                System.out.println("修改失敗");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(sta != null){
                try {
                    sta.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(con != null){
                try {
                    con.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

這樣一看,很明顯每一個操作都是在重複獲取連接、關閉資源等基礎操作,所以這塊我們可以在utils包封裝一個工具類出來,至於工具類的使用放在後面實現登錄的代碼裏:

/**
 * JDBC工具類要有兩個方法,一是註冊驅動獲取鏈接,二是釋放資源
 * 注意:工具類的方法一般都是靜態方法
 */
public class JdbcUtils {
    private static String url;
    private static String user;
    private static String password;
    private static String driver;
    //讀取配置文件:期望文件的讀取只讀取一次,而靜態代碼塊隨着類的加載而加載,所以用靜態代碼塊讀取配置文件中的資源
    static{
        Properties properties = new Properties();
        try {
            //獲取src下文件路徑---->Class.loader 類加載器
            ClassLoader classLoader = JdbcUtils.class.getClassLoader();
            URL res = classLoader.getResource("Jdbc.properties");
            String path = res.getPath();
            //加載文件
            properties.load(new FileReader(path));
            //獲取屬性,賦值
            url = properties.getProperty("url");
            user = properties.getProperty("user");
            password = properties.getProperty("password");
            driver = properties.getProperty("Driver");
            //加載驅動
            Class.forName(driver);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    //獲取連接
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url,user,password);
    }

    //釋放資源,因爲有兩種情況,所以寫兩個方法實現方法的重載
    public static void release(Statement state,Connection conn){
        if(state != null){
            try {
                state.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn != null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    public static void release(ResultSet res,Statement state,Connection conn){
        if(res != null){
            try {
                res.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(state != null){
            try {
                state.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn != null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

3.詳解各個對象

1)DriverManager:驅動管理對象

       1. 註冊驅動    static void registerDriver(Driver driver)

        註冊與給定的驅動程序DriverManager

        但我們代碼中用Class.forName("com.mysql.cj.jdbc.Driver");

        有什麼關係呢?

        通過源碼發現在com.mysql.cj.jdbc.Driver下有個靜態代碼塊,代碼塊裏使用了registerDriver

        2. 獲取數據庫連接    static Connection getConnection(String url,Stirng user,String password)

                                         這裏url = jdbc:mysql://IP:端口號/數據庫名

2)Connection:數據庫連接對象

        1.獲取執行sql的對象    Statement createStatement();

                                             PrepareStatement prepareStatement(String sql);

        2.管理事務

                   開啓事務:setAutoCommit(boolean autuCommit);參數設置爲false

                   提交事務:commit();

                   回滾事務:rollbacl();

3)Statement:執行sql的對象

        1. boolean execute(String sql);      可以執行任意的sql

        2. int executeUpdate(String sql);

            執行DML(insert,update,delete)語句、DLL(表的create、drop、alter)語句,返回值是影響的行數。

        3. ResultSet executeQuery(String sql);      執行DQL(select)語句

這塊代碼就不貼出來了,就是注意不同的sql語句後面執行的時候調用不同的方法就行了。

4)ResultSet:結果集對象,封裝返回結果的

        next();      遊標向下移動一行,最開始默認指向的是標題欄,所以就有下面代碼中的res.next()

        getXxx(參數);      獲取返回值,比如int getInt()

        get方法的參數有兩種情況:

        int代表列的編號,從1開始,比如getString(1) 獲取第一列的值;

        String代表列的名稱,比如getString("name")

使用步驟:

1.遊標向下移動一行

2.判斷是否有數據

3.獲取數據

此時熟悉前面這部分的使用,我們寫一個實現登錄邏輯的代碼,其中數據庫的連接及關閉資源都使用了工具類:

/**
 * 需求:通過鍵盤輸入用戶名和密碼
 *       判斷用戶是否登錄成功
 */
public class JdbcLogin {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入用戶名:");
        String name = sc.next();
        System.out.println("請輸入密碼:");
        String password = sc.next();
        boolean flag = new JdbcLogin().logIn2(name, password);
        if(flag){
            System.out.println("登陸成功!");
        }else{
            System.out.println("登陸失敗...");
        }
    }

    //登錄方法
    public boolean logIn(String usename,String password){
        //連接數據庫判斷是否登陸成功
        Connection connection = null;
        Statement statement = null;
        ResultSet res = null;
        if(usename == null || password == null){
            return false;
        }
        try {
            connection = JdbcUtils.getConnection();
            String sql = "select * from user where username = '"+usename+"' and password = '"+password+"'";
            statement = connection.createStatement();
            res = statement.executeQuery(sql);
            return res.next();//返回的就是一個Boolean類型值,代替了if語句
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(res,statement,connection);
        }
        return false;
    }
}

5)reperPreparedStatement:也是執行sql對象,但比Statement功能強大

1.SQL注入問題:在拼接sql時會有sql的特殊關鍵字參與字符串的拼接,會造成安全性問題

2.解決SQL注入問題:使用PreparedStatement對象來解決

3.預編譯SQL:參數使用?作爲佔位符

4.使用步驟在sql語句時:

        1)用?作爲佔位符寫sql語句

        2)在PreparedStatement(sql)方法中要傳入sql作爲參數

        3)給佔位符?賦值:setXxx(參數1,參數2);

參數1---?的位置編號(從1開始)

參數2---?的值

        4)在下一步執行sql接收返回結果時就不需要傳遞sql參數了

之前寫的sql語句是靜態sql,用reperPreparedStatement獲取執行對象後是這樣的:對比上一個登錄實現代碼來理解:

public class JdbcLogin {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入用戶名:");
        String name = sc.next();
        System.out.println("請輸入密碼:");
        String password = sc.next();
        boolean flag = new JdbcLogin().logIn2(name, password);
        if(flag){
            System.out.println("登陸成功!");
        }else{
            System.out.println("登陸失敗...");
        }
    }

    /**
     * 使用preparedstatement的登錄方法的實現
     */
    public boolean logIn2(String username,String password){
        //連接數據庫判斷是否登陸成功
        Connection connection = null;
        PreparedStatement  statement = null;
        ResultSet res = null;
        if(username == null || password == null){
            return false;
        }
        try {
            connection = JdbcUtils.getConnection();
            String sql = "select * from user where username = ? and password = ?";
            statement = connection.prepareStatement(sql);//此處傳參
            //注意給?賦值
            statement.setString(1,"username");
            statement.setString(2,"password");

            res = statement.executeQuery();//此處不需要傳參
            return res.next();

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(res,statement,connection);
        }
        return false;
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章