Java之JDBC詳談(資料庫)

一、了解JDBC

  1. JDBC是什麼?
    Java DataBase Connectivity(Java語言連接資料庫)
  2. JDBC的本質
    JDBC是SUN公司制定的一套介面(interface)
    java.sql.*(這個軟體包下有很多介面)
    開始面向介面編程,面向抽象編程,不要面向具體編程。
  3. JDBC編程六步(需要背會)
  • 第一步:註冊驅動(告訴Java程式,即將要連接的是哪個資料庫)
  • 第二步:獲取連接
  • 第三步:獲取資料庫操作對象(專門執行sql語句的對象)
  • 第四步:執行SQL語句(DQL DML)
  • 第五步:處理查詢結果集
  • 第六步:釋放資源

二、連接資料庫、實現用戶登錄

2.1前期準備

  • 還需要導入一個資料庫驅動包,mysql-connector-java-5.1.47.jar
  • url:包括協議、IP、PORT(埠)、資源名
  • mysql的url:jdbc:mysql://localhost:3306/smbms?useUnicode=true&characterEncoding=utf8&useSSL=false
    • jdbc:mysql:// 協議
    • localhost IP地址
    • 3306 mysql資料庫埠號
    • smbms 具體的資料庫實例名
public class JdbcTest {
    public static void main(String[] args) throws SQLException {
        try {
            //1、註冊驅動
            DriverManager.registerDriver(new com.mysql.jdbc.Driver());//這是一種載入驅動方式
            //這是另外一種載入驅動方式,我們從文件中讀資訊
            FileInputStream file = new FileInputStream("db.properties");
            //創建Map集合對象
            Properties properties = new Properties();
            //將文件資訊以鍵值對的形式載入出來
            properties.load(file);


            //還可以使用一個比較簡便的
            ResourceBundle bundle = ResourceBundle.getBundle("文件名");
            String driver = bundle.getString("key");


            //獲取文件資訊
            String driver = properties.getProperty("driver");
            String url = properties.getProperty("url");
            String username = properties.getProperty("username");
            String password = properties.getProperty("password");
            //通過反射載入驅動
            Class.forName(driver);
            System.out.println(driver);
            //2、獲取連接
            Connection connection = DriverManager.getConnection(url, username, password);
            System.out.println(connection);
            //3、獲取執行sql的對象
            Statement statement = connection.createStatement();
            String sql = "select * from smbms_role";
            //4、執行sql語句5、返回結果集
            ResultSet resultSet = statement.executeQuery(sql);
            resultSet.next();
            System.out.println(resultSet.getInt("id"));
            //6、釋放資源
            resultSet.close();
            statement.close();
            connection.close();
          //關閉資源時,必須從小到大按順序關閉,並且每個都要try--catch
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
//多寫幾遍,多查看API文檔,了解每個類具體幹什麼的,你就懂了,也就學會了。
  • 增刪改用int executeUpdate(insert/delete/update)
  • 查詢用ResulSet executeQurey(select)
  • 查詢時用boolean result.next(),若當前有數據則返回true,若沒有則false
  • JDBC的下標時從1開始,而不是0

2.2用戶登錄程式碼實現

public class LoginTest {
    public static void main(String[] args) {
        //1.獲取用戶登錄資訊
        Map<String,String> userInfo = userInfo();
        //2.驗證用戶密碼是否正確
        boolean loginResult = userLogin(userInfo);
        System.out.println(loginResult?"登錄成功" : "登錄失敗");
    }


    //獲取用戶登錄資訊
    public static Map<String,String> userInfo() {
        Scanner scan = new Scanner(System.in);
        System.out.println("輸入用戶名:");
        String username = scan.next();
        System.out.println("輸入密碼:");
        String password = scan.next();
        HashMap<String, String> user = new HashMap<>();
        user.put("username",username);
        user.put("password",password);
        return user;
    }
    //jdbc
    public static boolean userLogin(Map<String,String> userInfo) {
        boolean falg = false;
        Connection conn = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            String username = userInfo.get("username");
            String password = userInfo.get("password");
            //1.載入驅動
            Class.forName("com.mysql.jdbc.Driver");
            //2.獲取連接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/smbms?useUnicode=true&characterEncoding=utf8&useSSL=false", "root", "200506lx");
            //3.獲取操作對象
            statement = conn.createStatement();
            //4.執行sql
            //5.返回結果
            String sql = "select * from smbms_user where userCode = '"+username+"'and userPassword = '"+password+"'";
            resultSet = statement.executeQuery(sql);
            if(resultSet.next()) {
                falg = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 6.釋放資源
            if(resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        return falg;
    }
}

三、sql注入問題

  • asd'or'1'='1
  • 解決SQL注入問題
    • 只要用戶提供的資訊不參與SQL語句的編譯過程,問題就解決了
    • 即使用戶提供的資訊中含有SQL語句的關鍵字,但是沒有參與編譯,不起作用。
    • 要想用戶資訊不參與SQL語句的編譯,那麼必須使用java.sql.PreparedStatement
    • PreparedStatement這個介面繼承了java.sql.Statement
    • 屬於預編譯的資料庫操作對象,預先對SQL語句的框架進行編譯,然後再給SQL語句傳值
public static boolean userLogin(Map<String,String> userInfo) {
        boolean falg = false;
        Connection conn = null;
        PreparedStatement ps = null;//將Statement換成PreparedStatement
        ResultSet resultSet = null;
        try {
            String username = userInfo.get("username");
            String password = userInfo.get("password");
            //1.載入驅動
            Class.forName("com.mysql.jdbc.Driver");
            //2.獲取連接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/smbms?useUnicode=true&characterEncoding=utf8&useSSL=false", "root", "200506lx");
            //3.獲取操作對象
            //一個?就是一個佔位符,接受一個值
            String sql = "select * from smbms_user where userCode = ? and userPassword = ?";
            ps = conn.prepareStatement(sql);
            ps.setString(1,username); //1代表第一個?,給他設置值username
            ps.setString(2,password); //JDBC下標從1開始
            //4.執行sql
            //5.返回結果
            resultSet = ps.executeQuery();
            if(resultSet.next()) {
                falg = true;
            }
        }
}
  • 這樣我們就解決了SQL注入問題

四、對比Statement和PreparedStatement

  • Statement存在sql注入問題,PreparedStatement解決了sql注入問題
  • Statement是編譯一次執行一次,PreparedStatement是編譯一次,可執行n次,效率較高。
  • PreparedStatement會在編譯階段做類型檢查
  • 但是也有Statement用的地方。

五、JDBC事務演示

  • JDBC中只要執行任意一條DML語句,就提交一次
  • 記住三行程式碼搞定
  • conn.setAutoCommit(false)//將自動提交機制修改為手動提交機制,開啟事務
  • conn.commit();//提交事務
  • conn.rollback();//事務回滾

六、JDBC工具類的封裝

public class DButil {
    /*
    工具類中的構造方法都是私有的
    因為工具類中的程式碼都是靜態的,不需要new對象,直接採用類名調用
     */
    private DButil(){
    }
    private static final String driver;
    private static final String url;
    private static final String username;
    private static final String password;
    //靜態程式碼塊隨著類的載入而載入,並且只載入一次
    static {
        ResourceBundle rb = ResourceBundle.getBundle("db.properties");
        driver = rb.getString("driver");
        url = rb.getString("url");
        username = rb.getString("username");
        password = rb.getString("password");
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    //獲取資料庫的連接
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url,username,password);
    }
    //資料庫資源關閉
    public static  void closeResource(Connection conn, PreparedStatement ps, ResultSet rs) {
        if(conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(ps != null) {
            try {
                ps.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

七、結尾

  • 對於資料庫的JDBC內容就總結這麼多,若想深入學習等待後續更新,基礎部分掌握這些足矣。如果有不足之處,希望大家多多包涵,多多支援。如果有不懂的地方可以直接私信問我,歡迎來訪!
  • 我將會繼續更新關於Java的學習知識,感興趣的小夥伴可以關注一下。
  • 文章寫得比較走心,用了很長時間,絕對是copy過來的!
  • 尊重每一位學習知識的人,同時也尊重每一位分享知識的人。
  • 😎你的點贊與關注,是我努力前行的無限動力。🤩
Tags: