JDBC

1、什麼是jdbc

java database Connector java與數據庫的連接器
一套接口,是java代碼與數據庫的橋樑

2、重要接口和類

1)java.sql.Connection (連接接口--代表了java代碼與數據庫服務器之間的連接)
2)java.sql.Statement (語句接口--代表了語句對象,可以用來執行各種sql)
3)java.sql.ResultSet (結果集接口--代表查詢結果)
4)DriverManager (驅動管理器) 輔助類 -- 獲取Connection連接
5)java.sql.Driver (驅動接口)
6)java.sql.SQLException 檢查異常, 需要處理

###3
1) 加載驅動 (在新版的jdbc中可以省略此步驟)只需要執行一次即可
Class.forName("com.mysql.jdbc.Driver");// mysql 5.1
Class.forName("com.mysql.cj.jdbc.Driver"); // mysql 8.8

2) 創建連接,創建Connection對象
// jdbc:mysql: 稱爲連接協議
// localhost: mysql服務器的ip地址 連接本電腦用 localhost
// 3306: 連接端口號
// test3: 數據庫名稱
// serverTimezone=GMT%2B8 設置連接時區與數據庫服務器一致 (連接8.0 mysql時新增 )

    String url = "jdbc:mysql://localhost:3306/test3?serverTimezone=GMT%2B8&useSSL=false"; // 數據庫的連接字符串
    String username="root"; // 數據庫用戶名
    String password="root"; // 數據庫的密碼(自己定義的數據庫密碼)
    以上三個定義可以寫在工具類中方便以後的使用

    Connection conn = DriverManager.getConnection(url, username, password);

常見問題:
(1):在連接過程中一旦發生異常:java.sql.SQLNonTransientConnectionException: Public Key Retrieval is not allowed
需要添加allowPublicKeyRetrieval=true參數,此異常一種可能的發生情況是MySQL服務重啓後,立刻用jdbc連接時

       (2):不寫 serverTimezone=GMT%2B8`參數,否則會出現異常:java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä',
            另外`GMT%2B8`也必須加 ,否則會出現連接方和數據庫時區不一致問題   

       (3):WARN: Establishing SSL connection without server's identity verification is not recommended
              要消除這個警告信息,需要加入參數`useSSL=false   參數之間連接用&

3) 創建Statement 對象
    Statement stmt = conn.createStatement();

4) 執行sql語句(執行增刪改或查詢)

   stmt.executeUpdate(sql) // 用來執行 insert, update, delete   返回結果是int 類型 表示影響的行數
   stmt.executeQuery(sql)  // 用來執行 select

   stmt.execute(sql)       //都可以執行
        返回值是boolean類型 如果執行了增刪改,返回false, 如果執行的是查詢,那麼返回true,

5)結果集
ResultSet rs = stmt.executeQuery(sql);
rs.next();返回的是boolean值表示是否有下一條記錄

 next()方法用來移動到下一行記錄 getXXX方法用來獲取某列數據
 while (rs.next()) {
    int sid = rs.getInt(1);            //(1) 代表從第幾行開始
    String sname = rs.getString(2);
    Date birthday = rs.getDate(3);
    String sex = rs.getString(4);

   }
 情況1: getXXX(int 列下標) 用來獲取結果集中某一列的數據,其中XXX爲數據類型,如果是字符串使用 getString 如果是整數,使用getInt ... ,列下標從1開始
 情況2: getXXX(int 列名) 用來獲取結果集中某一列的數據,其中XXX爲數據類型,如果是字符串使用 getString 如果是整數,使用getInt
      如:int deptno = rs.getInt("deptno");
        String dname = rs.getString("dname");
        String loc = rs.getString("loc");

6) 關閉資源 先打開的後關閉
rs.close(); // 關閉ResultSet
stmt.close(); // 關閉Statement對象
conn.close(); // 關閉數據庫連接

###4 獲取自增列的值 Statement.RETURN_GENERATED_KEYS 代表自增的值

Statement stmt = conn.createStatement();
String sql = "insert into student(sid,sname,birthday,sex) values (null,'XXX','1999-1-1','男')";
stmt.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS);
ResultSet rs = stmt.getGeneratedKeys();
rs.next();
System.out.println(rs.getInt(1));

###5 sql 注入×××問題

問題: Connection conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
Statement stmt = conn.createStatement();
// 拼接字符串的辦法生成了sql語句
String sql = "select * from user where username='" +username+"' and password='"+password+"'";

如果結果爲:String password = "' or '1=1"; 會與之匹配從而登錄成功

解決方法: // PreparedStatement 預編譯的Statement ,可以避免SQL注入×××漏洞
// 讓代碼的可讀性更好

   Connection conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
    // sql語句是預先準備好的, 用?作爲值的佔位符

    String sql  = "select * from USER where username=? and password=?";
    PreparedStatement stmt = conn.prepareStatement(sql);
    // 給sql語句中的? 賦值
    stmt.setString(1, username); // 將username變量賦值給sql語句中第一個?, ?下標從1開始

    stmt.setString(2, "aaa' or '1'='1"); // 會將整個值當做一個整體,把or當做了值而不是關鍵字
    ResultSet rs = stmt.executeQuery();; // 會將sql語句以及通過set方法設置的參數值,一起發送給數據庫服務器

例: public static boolean login2(String deptno,String dname) {
Connection conn = null;
PreparedStatement pre = null;
ResultSet rst =null;
try {
conn = DriverManager.getConnection(URL, username, password);
String sql = "select * from emp where deptno=?and ename=?" ;
pre = conn.prepareStatement(sql);
pre.setString(1, deptno);
pre.setString(2, dname);
rst = pre.executeQuery();
if(rst.next()){
return true;
}else{
return false;
}
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("失敗",e); //無返回值拋出異常
}finally {
if(rst!=null){
try {
rst.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (pre!=null){
try {
pre.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}

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