第28次文章:簡單了解JDBC(續上周)
- 2019 年 10 月 8 日
- 筆記
這周的學習緊接上周學習文章哈!
在上次文章的末尾,我們提到了使用Statement介面時,可能發生SQL注入,不建議各位同學使用,為了解決SQL注入問題,我們使用另一種介面PreparedStatement()。(詳細情況請看上一篇文章:第27次文章:簡單了解JDBC)。
下面我們直接給出測試程式碼:
import com.mysql.jdbc.Connection; /** * 測試preparedStatement的基本用法 */ public class Demo03 { public static void main(String[] args) { Connection conn = null; PreparedStatement ps = null; try { //載入驅動類 Class.forName("com.mysql.jdbc.Driver"); conn = (Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc", "root", "123456"); String sql = "insert into t_user1 (username,pwd,regTime) value (?,?,?)"; ps = conn.prepareStatement(sql); // ps.setString(1, "peng");//參數索引是從1開始,而不是0 // ps.setString(2, "123456"); // ps.setDate(3, new java.sql.Date(System.currentTimeMillis()));//獲取當前時間 System.out.println("插入一條語句"); ps.setObject(1, "peng"); ps.setObject(2, "123456"); ps.setObject(3, new java.sql.Date(System.currentTimeMillis()));//獲取當前時間 } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); }finally { try { if(conn != null) { conn.close(); } } catch (SQLException e) { e.printStackTrace(); } try { if(ps != null) { ps.close(); } } catch (SQLException e) { e.printStackTrace(); } } } }
tips:
1.當我們將Statement介面轉換為PreparedStatement之後,我們在傳入參數的時候,使用的不再是拼字元串的方法,而是在SQL命令中的參數位置加入「?」,「?」代表著佔位符。這就屬於PreparedStatement防止SQL注入的關鍵所在。正如我們在注釋掉的上段程式碼中寫的那樣,使用PreparedStatement對象ps的setString,setDate等等方法來向每一個佔位符的位置傳遞參數,此時,我們可以通過對傳遞的參數進行預判斷,判斷傳入的參數是否符合String,int類型等等,這樣就防止了向SQL語句中傳入惡意指令情況的發生。
2.在向SQL語句中輸入參數的時候,我們不但可以使用setXXX的方法,還可以直接使用setObject()的方法傳遞參數,此時就可以不用考慮不同類型參數的問題了,全部當做Object類型進行傳遞。
3.在使用setDate()方法的時候,需要使用資料庫中的時間類型java.sql.Date,需要注意的是,我們傳入的時間類型並不是java中的Date類型。
(5)Result介面
-Statement執行SQL語句返回Result結果集。
-Result提供的檢索不同類型欄位的方法,常用的有:
- getString():獲得在資料庫里是varchar、char等資料庫類型的對象
- getFloa():獲得資料庫里是Float類型的對象
- getDate():獲得資料庫里是Date類型的對象
- getBoolean():獲得資料庫里是Boolean類型的對象
測試Result介面:
import com.mysql.jdbc.Connection; /** * 測試ResultSet結果集的基本用法 */ public class Demo04 { public static void main(String[] args) { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { //載入驅動類 Class.forName("com.mysql.jdbc.Driver"); conn = (Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc", "root", "123456"); String sql = "select id,username,pwd from t_user where id>?"; ps = conn.prepareStatement(sql); ps.setObject(1, 1);//取出所有id大於等於2的記錄 rs = ps.executeQuery(); while(rs.next()) { System.out.println(rs.getInt(1)+"---"+rs.getString(2)+"---"+rs.getInt(3));//一次取出第1列,第2列,第3列 } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); }finally { try { if(conn != null) { conn.close(); } } catch (SQLException e) { e.printStackTrace(); } try { if(ps != null) { ps.close(); } } catch (SQLException e) { e.printStackTrace(); } try { if(rs != null) { rs.close(); } } catch (SQLException e) { e.printStackTrace(); } } } }
tips:
1.在這段程式碼中,我們依然使用PreparedStatement類型進行傳輸參數,使用「?」佔位符,向佔位符中傳遞我們需要大於的參數值。
2.在我們使用Result介面的時候,我們可以將其類比為一個容器,接納所返回id大於2的結果。再編寫一個while循環將結果集中的內容輸出。其中的rs.next()方法類似於迭代器中的hasNext()方法。
(6)依序關閉使用的對象及連接
Result——>Statement——>Connection
(7)批處理
-Batch
-對於大量的批處理,建議使用Statement,因為PrepareStatement的預編譯空間有限,當數據量特別大時,會發生異常。
測試批處理操作:
import com.mysql.jdbc.Connection; /** * 測試批處理的基本用法 */ public class Demo05 { public static void main(String[] args) { Connection conn = null; Statement stmt = null; ResultSet rs = null; try { //載入驅動類 Class.forName("com.mysql.jdbc.Driver"); conn = (Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc", "root", "123456"); conn.setAutoCommit(false); //設為手動提交 long start = System.currentTimeMillis(); stmt = conn.createStatement(); for (int i=0;i<2000;i++) { stmt.addBatch("insert into t_user (username,pwd,regTime) values ('peng"+i+"',666,now())"); } stmt.executeBatch(); conn.commit(); //提交事務 long end = System.currentTimeMillis(); System.out.println("插入兩萬條語句,耗時(毫秒):"+(end - start)); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); }finally { try { if(conn != null) { conn.close(); } } catch (SQLException e) { e.printStackTrace(); } try { if(stmt != null) { stmt.close(); } } catch (SQLException e) { e.printStackTrace(); } try { if(rs != null) { rs.close(); } } catch (SQLException e) { e.printStackTrace(); } } } }
結果圖:

tips:
在批處理需要注意的兩點,第一就是需要將PreparedStatement介面更換為Statement介面,另一個需要注意的點是,需要將鏈接的事務提交設為手動提交。