一、資料庫驅動的概念、JDBC
資料庫廠商提供的用來運算元據庫用的jar包就是資料庫驅動。各個廠商如果提供各自的資料庫驅動的話會導致開發人員學習成本太高,所以sun公司提供了一套資料庫驅動應該遵循的介面規範,這套規範就叫做JDBC,本質上是很多的介面。
由於所有的資料庫驅動都遵循JDBC規範,我們在學習和使用資料庫時只要學習JDBC中的介面就可以了。
二、JDBC快速入門
*在資料庫中建立好表
*在程式中匯入資料庫驅動包
1.註冊資料庫驅動
DriverManager.registerDriver(new Driver());//缺點一:觀察mysqlDriver原始碼發現此方法導致了資料庫驅動被註冊了兩次。缺點二:整個程式域mysql資料庫驅動繫結增加了耦合性
Class.forName(“com.mysql.jdbc.Driver”);
2.獲取連線
DriverManager.getConnection(url, user, password);
~url的寫法:
Oracle寫法:jdbc:oracle:thin:@localhost:1521:sid
SqlServer—jdbc:microsoft:sqlserver://localhost:1433; DatabaseName=sid
MySql—jdbc:mysql://localhost:3306/sid
~url可以接的引數
user、password
useUnicode=true&characterEncoding=UTF-8
3.獲取傳輸器
createStatement():建立向資料庫傳送sql的statement物件。
prepareStatement(sql) :建立向資料庫傳送預編譯sql的PrepareSatement物件。
4.利用傳輸器執行sql語句獲取結果集
executeQuery(String sql) :用於向資料傳送查詢語句。
executeUpdate(String sql):用於向資料庫傳送insert、update或delete語句
execute(String sql):用於向資料庫傳送任意sql語句
5.遍歷結果集取出結構
ResultSet以表的樣式在記憶體中儲存了查詢結果,其中還維護了一個遊標,最開始的時候遊標在第一行之前,每呼叫一次next()方法就試圖下移一行,如果移動成功返回true;
ResultSet還提供了很多個Get方法,用來獲取查詢結果中的不同型別的資料
除了next方法,還有以下方法可以用來遍歷結果集:
next():移動到下一行
Previous():移動到前一行
absolute(int row):移動到指定行
beforeFirst():移動resultSet的最前面。
afterLast() :移動到resultSet的最後面。
6.釋放資源
conn是一個有限的資源,用完立即要釋放表
stat佔用記憶體,所以使用完後也要釋放
rs佔用記憶體,所以使用完後也要釋放
釋放時後建立的先釋放
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
} finally{
rs = null;
}
}
if(stat != null){
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
} finally{
stat = null;
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
} finally{
conn = null;
}
}
package com.dzq.jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import com.mysql.jdbc.Driver; public class JDBCDemo1 { public static void main(String []args) throws SQLException{ //1.註冊資料驅動 DriverManager.registerDriver(new Driver()); //2.獲取資料庫 Connection conn= (Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/database01", "root", ""); //3.獲取傳輸器物件 Statement stat=conn.createStatement(); //4.利用傳輸器傳輸sql語句到資料庫中執行,獲取結果集物件 ResultSet rs=stat.executeQuery("select * from user"); //5.遍歷結果集 while(rs.next()){ String name=rs.getString("name"); System.out.println(name); } //6.關閉資源 rs.close(); stat.close(); conn.close(); } }
改進後前後對比:
package com.dzq.jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class JDBCDemo1 { public static void main(String []args) throws Exception{ //1.註冊資料驅動 //--由於mysql在Driver類的實現中自己註冊了一次,而我們又註冊了一次,於是會導致MySql驅動被註冊兩次 //--建立MySql的Driver物件時,導致了程式和具體的Mysql驅動綁死在了一起,在切換資料庫時需要改動java程式碼 // DriverManager.registerDriver(new Driver()); Class.forName("com.mysql.jdbc.Driver"); //2.獲取資料庫 Connection conn= (Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/database01", "root", ""); //3.獲取傳輸器物件 Statement stat=conn.createStatement(); //4.利用傳輸器傳輸sql語句到資料庫中執行,獲取結果集物件 ResultSet rs=stat.executeQuery("select * from user"); //5.遍歷結果集 while(rs.next()){ String name=rs.getString("name"); System.out.println(name); } //6.關閉資源 rs.close(); stat.close(); conn.close(); } }
再次改進,改善異常處理機制:
package com.dzq.jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class JDBCDemo1 { public static void main(String []args) { Connection conn=null; ResultSet rs=null; Statement stat=null; //1.註冊資料驅動 //--由於mysql在Driver類的實現中自己註冊了一次,而我們又註冊了一次,於是會導致MySql驅動被註冊兩次 //--建立MySql的Driver物件時,導致了程式和具體的Mysql驅動綁死在了一起,在切換資料庫時需要改動java程式碼 // DriverManager.registerDriver(new Driver()); try{ Class.forName("com.mysql.jdbc.Driver"); //2.獲取資料庫 conn= (Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/database01", "root", ""); //3.獲取傳輸器物件 stat=conn.createStatement(); //4.利用傳輸器傳輸sql語句到資料庫中執行,獲取結果集物件 rs=stat.executeQuery("select * from user"); //5.遍歷結果集 while(rs.next()){ String name=rs.getString("name"); System.out.println(name); } }catch(Exception e){ e.printStackTrace(); }finally{ //6.關閉資源 try { if(rs!=null){ rs.close(); } } catch (SQLException e) { e.printStackTrace(); }finally{ rs=null; } try { if(stat!=null){ stat.close(); } } catch (SQLException e) { e.printStackTrace(); }finally{ stat=null; } try { if(conn!=null){ conn.close(); } } catch (SQLException e) { e.printStackTrace(); }finally{ conn=null; } } } }
三、PreparedStatement
1.Sql注入:由於jdbc程式在執行的過程中sql語句在拼裝時使用了由頁面傳入引數,如果使用者惡意傳入一些sql中的特殊關鍵字,會導致sql語句意義發生變化,這種攻擊方式就叫做sql注入,參考使用者註冊登入案例。
2.PreparedStatement是Statement的孩子,不同的是,PreparedStatement使用預編譯機制,在建立PreparedStatement物件時就需要將sql語句傳入,傳入的過程中引數要用?替代,這個過程回導致傳入的sql被進行預編譯,然後再呼叫PreparedStatement的setXXX將引數設定上去,由於sql語句已經經過了預編譯,再傳入特殊值也不會起作用了。
3.PreparedStatement使用了預編譯機制,sql語句在執行的過程中效率比Statement要高。
四、大資料
1.mysql資料庫也可以直至在資料庫中儲存大文字和大二進位制資料,
Text
TINYTEXT(255)、TEXT(64k)、MEDIUMTEXT(16M)和LONGTEXT(4G)
Blob
TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB
2.JDBC去操作大文字:
~插入大文字:
ps = conn.prepareStatement("insert into Demo2Text values(null,?,?)");
ps.setString(1, "鋼鐵是怎樣練成");
File file = new File("1.txt");
ps.setCharacterStream(2, new FileReader(file), (int) file.length());
//1.Exception in thread "main" java.lang.AbstractMethodError: com.mysql.jdbc.PreparedStatement.setCharacterStream(ILjava/io/Reader;J)V
//ps.setCharacterStream(2, new FileReader(file), file.length());第三個引數是long型的是從1.6才開始支援的,驅動裡還沒有開始支援。
//解決方案:ps.setCharacterStream(2, new FileReader(file), (int)file.length());
//2.Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
//檔案大小過大,導致PreparedStatement中資料多大佔用記憶體,記憶體溢位
//-Xms256M-Xmx256M
//3.com.mysql.jdbc.PacketTooBigException: Packet for query is too large (10886466 > 1048576). You can change this value on the server by setting the max_allowed_packet' variable.
//資料庫連線傳輸用的包不夠大,傳輸大文字時報此錯誤
//在my.ini中配置max_allowed_packet指定包的大小
~查詢大文字:
Reader rd = rs.getCharacterStream("content");
3.JDBC操作大二進位制
~插入:
ps = conn.prepareStatement("insert into Demo3Blob values(null,?,?)");
ps.setString(1, "夢想的力量");
File file = new File("1.mp3");
ps.setBinaryStream(2, new FileInputStream(file), (int) file.length());
~查詢
InputStream in = rs.getBinaryStream("content");