Day43-JDBC

一、引言

1.1 如何操作數據

使用客戶端工具訪問數據庫,需要手工建立鏈接,輸入用戶名和密碼登錄,編寫SQL語句,點擊執行,查看操作結果(結果集或受影響行數)。


1.2 實際開發中,會採用客戶端操作數據庫嗎?

在實際開發過程中,當用戶的數據發生改變時,不可能通過客戶端操作執行SQL語句,因爲操作量過大,無法保證效率和正確性


二、JDBC(Java DataBase Connectivity)

2.1 什麼是JDBC?

JDBC(Java DataBase Connectivity) Java連接數據庫,可以使用Java語言連接數據庫完成CRUD操作


2.2 JDBC核心思想

Java中定義了訪問數據庫的接口,可以爲多種關係型數據庫提供統一的訪問方式。

由數據庫廠商提供驅動實現類(Driver數據庫驅動)


2.3 JDBC API

JDBC 是由多個接口和類進行功能實現

類型 全限定名 簡介
class java.sql.DriverManager 管理多個數據庫驅動類,提供了獲取數據庫連接的方法
interface java.sql.Connection 代表一個數據庫連接(當Connection不是NULL時,表示已連接一個數據庫)
interface java.sql.Statement 發送SQL語句到數據庫的工具
interface java.sql.ResultSet 保存SQL查詢語句的結果數據(結果集)
class java.sql.SQLException 處理數據庫應用程序時所發生的異常

2.4 環境搭建

  1. 在項目下新建 lib 文件夾,用於存放 jar 文件
  2. 將MySQL驅動文件mysql-connector-java-5.1.25-bin.jar 複製到項目的lib文件夾中
  3. 選中lib文件夾 右鍵選擇 add as library,點擊OK

三、JDBC開發步驟

3.1 註冊驅動

使用Class.forName(“com.mysql.jdbc.Driver”); 手動加載字節碼文件到JVM中

Class.forName("com.mysql.jdbc.Driver");

3.2 連接數據庫

  • 通過DriverManager.getConnection(url,user,password);獲得數據庫連接對象
    • URL:jdbc:mysql://localhost:3306/database
    • user:root
    • password:1234
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/database
?useUnicode=true&characterEncoding=utf8","root","1234");
  • URL(Uniform Resource Locator)統一資源定位符:由協議、IP、端口、SID(程序實例名稱)組成

3.3 獲取發送SQL的對象

通過Connection對象獲得Statement對象,用於對數據庫進行通用訪問的

Statement statement = connection.createStatement();

3.4 執行SQL語句

編寫SQL語句,並執行,接收執行後的結果

int result = statement.executeUpdate("update stu set  where ");
  • 注意:在編寫DML語句時,一定要注意字符串參數的符號是單引號 ‘值’
  • DML語句:增、刪、改時,執行的結果是受影響行數(int類型)。
  • DQL語句:查詢時,返回的是數據結果集(ResultSet結果集)

3.5 處理結果

接收並處理操作結果

if(result > 0){
	System.out.println("執行成功");
}
  • 受影響行數:邏輯判斷,方法返回
  • 查詢結果集:迭代、依次獲取

3.6 釋放資源

遵循的是先開後關的原則,釋放過程中用到的所有資源對象

statement.close();
connection.close();

四、 ResultSet(結果集)

在執行查詢SQL後,存放查詢到的結果集數據

4.1 接收結果集

ResultSet rs = statement.executeQuery(sql)

ResultSet rs = statement.executeQuery("SELECT * FROM stu");

4.2 遍歷ResultSet中的數據

ResultSet以表(Table)結構進行臨時結果的存儲,需要通過JDBC API將其中的數據進行依次獲取

  • 數據行指針:初始位置在第一行數據前,每調用一次boolean next()方法,ResultSet中指針向下移動一行,結果爲true,表示當前行有數據

  • rs.getXxx(“列名”); 根據列名獲得數據

  • rs.getXxx(整數下標); 代表根據列的編號順序獲得!從1開始

    boolean next() throws SQLException;//判斷rs結果集中下一行是否有數據


4.2.1 遍歷方法

int getInt(int columnIndex) throws SQLException;//獲得當前行的第N列的int值
int getInt(String columnLabel) throws SQLException;//獲得當前行columnLabel列的int值

注意:列的編號從1開始

4.3 綜合案例

對stu表所有的數據進行遍歷


4.3.1 根據列的名稱獲取

public class Test {
    public static void main(String[] args)  throws Exception{
        //1.註冊驅動
        Class.forName("com.mysql.jdbc.Driver");

        //2.獲得連接
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/companydb?useUnicode=true&characterEncoding=utf8","root","root");

        //3.獲取執行SQL的對象
        Statement statement = connection.createStatement();

        //4.編寫SQL語句
        String sql = "select student_id,student_name,sex,birthday,phone,GradeId from stu;";
        ResultSet resultSet = statement.executeQuery(sql);

        //5.處理結果 (結果集!)
        while(resultSet.next()){//判斷結果集中是否有下一行!
            //根據列名獲取當前行每一列的數據
            String student_id = resultSet.getString("student_id");
            String student_name = resultSet.getString("student_name");
            String sex = resultSet.getString("sex");
            String birthday = resultSet.getString("birthday");
            String phone = resultSet.getString("phone");
            int gradeId = resultSet.getInt("gradeId");
            System.out.println(student_id+"\t"+student_name+"\t"+sex+"\t"+birthday+"\t"+phone+"\t"+gradeId);
        }

        //6.釋放資源
        resultSet.close();
        statement.close();
        connection.close();

    }
}

4.3.2 根據列的下標獲取

 //5.處理結果 (結果集!)
        while(resultSet.next()){//判斷結果集中是否有下一行!
            //根據列的編號獲取當前行每一列的數據
            String student_id = resultSet.getString(1);
            String student_name = resultSet.getString(2);
            String sex = resultSet.getString(3);
            String birthday = resultSet.getString(4);
            String phone=  resultSet.getString(5);
            int gradeId  = resultSet.getInt(6);
            System.out.println(student_id+"\t"+student_name+"\t"+sex+"\t"+birthday+"\t"+phone+"\t"+gradeId);
 }

五、常見錯誤

  • java.lang.ClassNotFoundException 找不到類(類名書寫錯誤、沒有導入jar包)
  • com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException 與SQL語句相關的錯誤(表名列名書寫錯誤、約束錯誤、插入的值是String類型,但是沒有加單引號)建議:在客戶端工具中測試sql語句後,再粘貼到代碼中來
  • com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry ‘S1003’ for key ‘PRIMARY’ 原因:主鍵值已存在!更改要插入的主鍵值
  • com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:Unknown column ‘password’ in
    • 可能輸入的值的類型不對,確定插入元素時,對應的值的類型是否爭取

六、SQL注入問題

6.1 什麼是SQL注入

當用戶輸入的數據中有SQL關鍵字或語法時,並且參與了SQL語句的編譯,導致SQL語句編譯後條件結果爲true,一直得到正確的結果。稱爲SQL注入


6.2如何避免SQL注入

由於編寫的SQL語句,是在用戶輸入數據後,整合後再編譯成SQL語句。所以爲了避免SQL注入的問題,使SQL語句在用戶輸入數據前,SQL語句已經完成編譯,成爲了完整的SQL語句,再進行填充數據


七、 PreparedStatement

PreparedStatement接口繼承了Statement接口。執行SQL語句的方法沒有區別。

7.1 PreparedStatement的應用

作用:1.預編譯SQL語句,效率高!

			2.安全,避免SQL注入

			3.可以動態的填充數據,執行多個同構的SQL語句

7.1.1 參數標記

//1.預編譯SQL語句
PreparedStatement pstmt = connection.prepareStatement(sql);

注意:PreparedStatement應用時,SQL字符串的參數都由?符號站位,被稱爲參數標記。在執行該SQL語句前,要爲每個?參數賦值


7.1.2 動態參數綁定

pstmt.setXxx(下標,值); 參數下標是從1開始,爲指定佔位符下標綁定值

//2.爲佔位符下標賦值
pstmt.setString(1,username);
pstmt.setString(2,password);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章