JDBC總結1

攻城獅阿倫發表於2020-10-15

JDBC總結1

一、概述

  • 概念:JDBC(Java DataBase Connectivity),Java資料庫連線。
  • 本質:其實是官方(sun公司)定義的一套操作所有關係型資料庫的規則,即介面。各個資料庫廠商去實現這套介面,提供資料庫驅動jar包,把資料庫廠商寫的這套實現類,稱之為資料庫驅動。

結構演示:

二、使用

2.1 JDBC使用步驟

  1. 匯入驅動jar包 mysql-connector-java-5.1.37-bin.jar
    1. 複製mysql-connector-java-5.1.37-bin.jar到專案的libs目錄下
    2. .右鍵–>Add As Library
  2. 載入驅動jar包
  3. 獲取資料庫連線物件 Connection
  4. 定義sql操作語句
  5. 獲取執行sql語句的物件 Statement
  6. 執行sql,接受返回結果
  7. 處理結果
  8. 釋放資源

程式碼演示:

public class JDBC {
    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        //註冊驅動
        Class.forName("com.mysql.jdbc.Driver");
        //獲取資料庫連線物件 Connection
        String url = "jdbc:mysql://localhost:3306/mydb";
        Connection conn = DriverManager.getConnection(url, "root", "123");
        //獲取操作物件
        Statement statement = conn.createStatement();
        //傳送sql語句
        String sql = "insert into student(name,age,address) values('張無忌',20,'西安市')";
        //執行executeUpdate(sql) 增刪改的語句
        int count = statement.executeUpdate(sql);
        //處理結果
        System.out.println(count);
        if (count > 0) {
            System.out.println("插入成功");
        } else {
            System.out.println("插入失敗");
        }
        //釋放資源。
        conn.close();
        statement.close();
    }
}

2.1 詳解使用類

  1. Class.forName(“com.mysql.jdbc.Driver”); 載入驅動,也可以省略不寫。mysql5之後的驅動jar包可以省略註冊驅動的步驟。

    • 當你不寫時,Driver裡面存在的靜態程式碼塊會替你註冊。

      static {
           try {
               DriverManager.registerDriver(new Driver());
           } catch (SQLException var1) {
               throw new RuntimeException("Can't register driver!");
           }
      }
      
  2. DriverManager:驅動管理物件

    • Java提供的管理一組 JDBC 驅動程式的基本服務。
  3. Connection:獲取資料庫連線。

    連線方法:

    static Connection getConnection(String url, String user, String password)

    引數:

    1. url:指定連線的路徑。

      • 語法:jdbc:mysql://ip地址(域名):埠號/資料庫名稱
      • 例如:jdbc:mysql://localhost:3306/mydb

      提示:如果連線的是本機mysql伺服器,並且mysql服務預設埠是3306,則url可以簡寫為:jdbc:mysql:///資料庫名稱

    2. user:使用者名稱

    3. password:密碼

  4. Statement:獲取資料庫操作物件

  • 獲取操作物件的方法:Statement createStatement()
  1. 執行sql命令

    1. boolean b = statement.execute(sql);用來執行所有的SQL語句。該方法執行SQL語句可能返回多個結果。
      • 如果第一個結果為 ResultSet 物件,則返回 true
      • 如果其為更新計數或者不存在任何結果,則返回 false
    2. int i = statement.executeUpdate(sql);用來執行DML語句,用來對錶中資料進行增刪改。返回值是影響的行數。
    3. ResultSet rs = executeQuery(String sql);用來執行DQL語句,用來對錶進行查詢。該語句返回單個 ResultSet 物件。
  2. ResultSet:結果集物件,封裝查詢結果

    • boolean next(): 遊標向下移動一行,判斷當前行是否是最後一行末尾(是否有資料),如果是,則返回false,如果不是則返回true。
    • getXxx(引數):獲取資料
      • Xxx:代表資料型別。如: int getInt() ,String getString()
      • int:代表列的編號,從1開始。如:getString(1)
      • String:代表列名稱。如:getDouble(“balance”)

    程式碼演示:

    while (resultSet.next()) {
       int id = resultSet.getInt(1);
       String content = resultSet.getString("username");
       System.out.println(id + "---" + content);
    }
    
  3. PreparedStatement:執行sql的物件

    1. SQL隱碼攻擊問題:在拼接sql時,有一些sql的特殊關鍵字參與字串的拼接。會造成安全性問題。
      • 輸入使用者任意,輸入密碼:‘a’ or ‘a’ = 'a
      • sql:select * from user where username = 'fhdsjkf' and password = 'a' or 'a' = 'a'
    2. 解決sql注入問題:使用PreparedStatement物件來解決。
    3. 預編譯的SQL:引數使用?作為佔位符

    程式碼演示:

    public class JDBC2 {
        public static void main(String[] args) throws SQLException, ClassNotFoundException {
            Class.forName("com.mysql.jdbc.Driver");
            String url = "jdbc:mysql://localhost:3306/mydb";
            String user = "root";
            String password = "123";
            Connection conn = DriverManager.getConnection(url, user, password);
            String sql = "select * from user where username = ? and password = ?";
            PreparedStatement preparedStatement = conn.prepareStatement(sql);
            preparedStatement.setString(1, "張三");
            preparedStatement.setString(2, "123");
            ResultSet resultSet = preparedStatement.executeQuery();
            while (resultSet.next()) {
                int id = resultSet.getInt(1);
                String u = resultSet.getString(2);
                String p = resultSet.getString(3);
                System.out.println(id + "---" + u + "---" + p);
            }
            //釋放資源
            conn.close();
            preparedStatement.close();
            resultSet.close();
        }
    }
    

    注意:後期都會使用PreparedStatement來完成增刪改查的所有操作

    1. 可以防止SQL隱碼攻擊
    2. 效率更高

三、抽取JDBC工具類

  • 目的:簡化書寫
  • 使用配置檔案解決傳遞引數的問題properties

工具類

public class JDBCUtils {
    private static String url;
    private static String username;
    private static String password;
    private static String driver;
    //想要把獲取連線物件和釋放資源的操作,抽取到工具類當中

    private JDBCUtils() {
    }

    static {
        try {
            Properties pro = new Properties();
            pro.load(new FileInputStream("jdbc.properties"));
            //獲取資料,賦值
            url = pro.getProperty("url");
            username = pro.getProperty("username");
            password = pro.getProperty("password");
            driver = pro.getProperty("driver");
            //註冊驅動
            Class.forName(driver);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    //獲取連線物件
    public static Connection getConnection() throws SQLException {
        Connection connection = DriverManager.getConnection(url, username, password);
        return connection;
    }

    //釋放資源
    public static void close(Connection conn, Statement statement, ResultSet resultSet) throws SQLException {
        if (conn != null) {
            conn.close();
        }
        if (statement != null) {
            statement.close();
        }
        if (resultSet != null) {
            resultSet.close();
        }

    }
    //釋放資源
    public static void close(Connection conn, Statement statement) throws SQLException {
        if (conn != null) {
            conn.close();
        }
        if (statement != null) {
            statement.close();
        }
    }
}

配置檔案

url=jdbc:mysql://localhost:3306/mydb4
username=root
password=123
driver=com.mysql.jdbc.Driver

測試類

public class MyTest2 {
    public static void main(String[] args) throws SQLException {
        Connection conn = JDBCUtils.getConnection();
        String sql = "select * from user where id>?";
        PreparedStatement preparedStatement = conn.prepareStatement(sql);
        preparedStatement.setInt(1, 0);
        ResultSet resultSet = preparedStatement.executeQuery();
        while (resultSet.next()) {
            int id = resultSet.getInt(1);
            String content = resultSet.getString("username");
            System.out.println(id + "---" + content);
        }
        //釋放資源
        JDBCUtils.close(conn,preparedStatement,resultSet);
    }
}

四、JDBC控制事物

4.1 概述

  • 事務:一個包含多個步驟的業務操作。如果這個業務操作被事務管理,則這多個步驟要麼同時成功,要麼同時失敗。

  • 事物的ACID特性

    • 原子性(Atomicity):是指事務是一個不可分割的工作單位,事務中的操作要麼都發生,要麼都不發生。
    • 一致性(Consistency):事務必須使資料庫從一個一致性狀態變換到另外一個一致性狀態。
    • 隔離性(Isolation):多個使用者併發訪問資料庫時,資料庫為每一個使用者開啟的事務,不能被其他事務的運算元據所干擾,多個併發事務之間要相互隔離。
    • 永續性(Durability):是指一個事務一旦被提交,它對資料庫中資料的改變就是永久性的,接下來即使資料庫發生故障也不應該對其有任何影響。

4.2 事務操作和管理

  1. 操作:
    1. 開啟事務
    2. 提交事務
    3. 回滾事務
  2. 使用Connection物件來管理事務
    1. 開啟事務:setAutoCommit(boolean autoCommit) :呼叫該方法設定引數為false,即開啟事務
      • 注意:在執行sql之前開啟事務
    2. 提交事務:commit()
      • 當所有sql都執行完提交事務
    3. 回滾事務:rollback()
      • 在catch中回滾事務

4.3 程式碼演示

模擬張三給李四借錢:

  1. 當操作正常時,借錢過程正常進行。
  2. 當存在異常時,事物啟動回滾操作,避免損失。
public class JDBC1 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement ps1= null;
        PreparedStatement ps2= null;
        try {
            //1.獲取連線
            conn = JDBCUtils.getConnection();
            //開啟事務
            conn.setAutoCommit(false);
            //2.定義sql
            //2.1 張三 - 500
            String sql1 = "update account set balance = balance - ? where id = ?";
            //2.2 李四 + 500
            String sql2 = "update account set balance = balance + ? where id = ?";
            //3.獲取執行sql物件
            ps1 = conn.prepareStatement(sql1);
            ps2 = conn.prepareStatement(sql2);
            //4. 設定引數
            ps1.setDouble(1,500);
            ps1.setInt(2,1);

            ps2.setDouble(1,500);
            ps2.setInt(2,2);
            //5.執行sql
            ps1.executeUpdate();
            // 手動製造異常
            int i = 3/0;
            ps2.executeUpdate();
            //提交事務
            conn.commit();
        } catch (SQLException e) {
            //事務回滾
            try {
                if(conn != null) {
                    conn.rollback();
                }
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        }finally {
            try {
                JDBCUtils.close(conn,ps1);
                JDBCUtils.close(null,ps2);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}