天天看點

JDBC-04-使用PreparedStatement實作CRUD操作

使用PreparedStatement實作CRUD操作

​​相關完整代碼前往Github​​

文章目錄

  • ​​使用PreparedStatement實作CRUD操作​​
  • ​​Statement操作資料庫的弊端​​
  • ​​PreparedStatement的使用​​
  • ​​PreparedStatement vs Statement​​
  • ​​Java與SQL對應資料類型轉換表​​
  • ​​ResultSet與ResultSetMetaData​​
  • ​​ResultSet​​
  • ​​ResultSetMetaData​​
  • ​​JDBC API小結​​
  • ​​使用Statement弊端​​

通路和操作資料庫

  • 資料庫連接配接被用于向資料庫伺服器發送指令和sql語句,并接受資料庫伺服器傳回來的結果,其實一個資料庫連接配接就是一個socket連接配接
  • 在java.sql包中由3 個接口分别定義了對資料庫的調用的不同方式:

Statement:用于執行靜态sql語句,并傳回它所生成結果的對象。

PrepatedStatement:sql語句别預編譯并儲存在對象中,可以使用次對象多次高效的執行該語句

CallableStatement:用于執行 SQL 存儲過程

JDBC-04-使用PreparedStatement實作CRUD操作

Statement操作資料庫的弊端

  • 通過connection對象的​

    ​createStatement()​

    ​方法建立對象,該對象用于執行靜态的SQL語句,并且傳回執行結構
  • statement接口定義了下列方法執行SQL語句

int executeUpdate(String sql) 執行更新insert,update delete

resultset executeQuery(String sql):執行查詢操作SELECT

  • 使用statement操作資料庫表存在弊端

問題一 存在拼串操作,繁瑣

問題二:存在SQL注入問題

  • sql注入問題是利用某些系統沒有對使用者輸入的資料進行從分的檢查,而在使用者輸入資料注入非法的SQL語句段或指令(如:​

    ​SELECT user, password FROM user_table WHERE user='a' OR 1 = ' AND password = ' OR '1' = '1'​

    ​) ,進而利用系統的 SQL 引擎完成惡意行為的做法。
  • 對于java而言,要防範sql注入,隻要用PreparedStatement(從Statement擴充而來) 取代statement就可以了
JDBC-04-使用PreparedStatement實作CRUD操作

PreparedStatement的使用

  • 可以通過調用Connection 對象的​

    ​preparedStatement(String sql)​

    ​​方法擷取​

    ​preparedStatement​

    ​對象
  • ​preparedStatement​

    ​​是​

    ​Statement​

    ​的子接口,他表示一條預編譯過的SQL語句
  • ​preparedStatement​

    ​​對象所表示的SQL語句的參數用(?)表示,調用​

    ​preparedStatement​

    ​對象的setXxx() 方法來設定這些參數.
  • setXxx() 方法中有兩個參數,第一個參數是設定sql語句中的參數的索引(從一開始),第二個是設定的SQL語句中的參數的值

PreparedStatement vs Statement

  • 提高了代碼的而可讀性和可維護性
  • PreparedStatement能最大可能提高性能
DBServe會對​

​預編譯​

​語句提供性能優化,因為預編譯語句可能會被重複使用,是以語句在被DBServer的編譯器編譯後的執行代碼被緩存下載下傳,下次調用的時候隻要是相同的預編譯語句就不需要編譯,隻要将參數直接傳入編譯過的語句執行代碼,就會得到執行

在​

​statement​

​​語句中,即使是相同操作但是因為資料不一樣,是以整個語句本身不能比對,沒有緩存語句的意義,事實是沒有資料庫會對普通語句編譯後的執行代碼緩存這樣​

​每執行一次都要對傳入的語句編譯一次。​

(文法檢查,語義檢查,翻譯成二進制指令,緩存)

  • PreparedStatement 可以防止 SQL 注入
  • PreparedStatement 可以實作批量操作,效率高 …Statement無
  • PreparedStatemen可以操作Blob類型變量…Statement不能

Java與SQL對應資料類型轉換表

Java類型 SQL類型
boolean BIT
byte TINYINT
short SMALLINT
int INTEGER
long BIGINT
String CHAR,VARCHAR,LONGVARCHAR
byte array BINARY , VAR BINARY
java.sql.Date DATE
java.sql.Time TIME
java.sql.Timestamp TIMESTAMP

ResultSet與ResultSetMetaData

ResultSet

查詢需要調用​

​PreparedStatement​

​​的​

​executeQuery​

​方法,查詢結果是一個Resultset對象

  • ResultSet對象以邏輯表格的形式封裝了執行資料庫的結果集,ResultSet 接口由資料庫廠商提供
  • ResultSet傳回的實際是一張資料表,有一個指針指向資料表的第一條資料的前面
  • ResultSet 對象維護一個指向目前資料行的遊标,初始的時候,遊标在第一行之前,可以通過 ResultSet 對象的 next() 方法移動到下一行.調用next()方法檢測下一行是否有效,若有效,該方法傳回true,且指針下移相當于Iterator對象的 hasNext() 和 next() 方法的結合體。
  • 當指針指向一行時,可以通過調用 getXxx(int index) 或 getXxx(int columnName) 擷取每一列的值。
  • 例如: getInt(1), getString(“name”)
  • 注意:Java與資料庫互動涉及到的相關Java API中的索引都從1開始。

ResultSetMetaData

可用于擷取關于 ResultSet 對象中列的類型和屬性資訊的對象,ResultSetMetaData meta = rs.getMetaData();

  • ​getColumnName(int column)​

    ​:擷取指定列的名稱
  • ​getColumnLabel(int column)​

    ​:擷取指定列的别名
  • ​getColumnCount()​

    ​:傳回目前 ResultSet 對象中的列數。
  • getColumnTypeName(int column):檢索指定列的資料庫特定的類型名稱。
  • getColumnDisplaySize(int column):訓示指定列的最大标準寬度,以字元為機關。
  • ​isNullable(int column)​

    ​:訓示指定列中的值是否可以為 null。
  • isAutoIncrement(int column):訓示是否自動為指定列進行編号,這樣這些列仍然是隻讀的。

問題1:得到結果集後, 如何知道該結果集中有哪些列 ? 列名是什麼?

需要使用一個描述 ResultSet 的對象, 即 ResultSetMetaData

問題2:關于ResultSetMetaData

  1. 如何擷取 ResultSetMetaData: 調用 ResultSet 的 getMetaData() 方法即可
  2. 擷取 ResultSet 中有多少列:調用 ResultSetMetaData 的 getColumnCount() 方法
  3. 擷取 ResultSet 每一列的列的别名是什麼:調用 ResultSetMetaData 的getColumnLabel() 方法

釋放資源:

  • 釋放ResultSet, Statement,Connection。
  • 資料庫連接配接(Connection)是非常稀有的資源,用完後必須馬上釋放,如果Connection不能及時正确的關閉将導緻系統當機。Connection的使用原則是盡量晚建立,盡量早的釋放。
  • 可以在finally中關閉,保證及時其他代碼出現異常,資源也一定能被關閉。

JDBC API小結

  • 兩種思想
  • 面向接口程式設計的思想
  • ORM思想(object relational mapping)
  • 一個資料表對應一個java類
  • 表中的一條記錄對應java類的一個對象
  • 表中的一個字段對應java類的一個屬性
sql是需要結合列名和表的屬性名來寫。注意起别名。
  • 兩種技術
  • JDBC結果集的中繼資料:ResultSetMetaData
  • 擷取列數:getColumnCount()
  • 擷取列的别名:getColumnLabel()
  • 通過反射,建立指定類的對象,擷取指定的屬性并指派

使用Statement弊端

弊端:

問題一 存在拼串操作,繁瑣

問題二:存在SQL注入問題

  • sql注入問題是利用某些系統沒有對使用者輸入的資料進行從分的檢查,而在使用者輸入資料注入非法的SQL語句段或指令(如:​

    ​SELECT user, password FROM user_table WHERE user='a' OR 1 = ' AND password = ' OR '1' = '1'​

    ​) ,進而利用系統的 SQL 引擎完成惡意行為的做法。
Scanner scan = new Scanner(System.in);
String name = scan.next();      
String sql = "insert into customers(name,email,birth)values('" + name +"','"+email+"','"+birth+"')";
SQL注入:
SELECT user,password FROM user_table WHERE user = '1' or ' AND password = '=1 or '1' = '1'      
  • Statement沒辦法操作Blob類型變量
  • Statement實作批量插入時,效率較低