由淺到深學習JDBC一

JDBC:


雖然由於快節奏的開發,編程速度的追求,越愛越多的MVC框架出現,比如持久層的hibernate,

mybatis等等,他們對Dao層的支持都很強大,既快速,又簡便。但是他們的底層同樣是使用了JDBC,

爲了追求高速簡便,我們可以不使用JDBC,但一定要了解JDBC。瞭解JDBC也有助於學習其他持久層框架。


java和數據庫交互需要中間程序作爲中轉。在很早以前,數據庫廠商還沒有一套統一的API作爲

java語言和數據庫的接口,開發程序是一件很頭疼的事。對不同的數據庫需要寫不同的程序來作爲交互。

     java訪問-----oracle程序-----oracle數據庫

     java訪問------mysql程序------mysql數據庫

     java訪問-------db2程序--------db2數據庫

那到底什麼是JDBC呢:

    JDBC是代表Java數據庫連接,這對java編程語言和廣泛的數據庫之間獨立於數據庫的連接標準的Java API

     有了JDBC開發就統一了很多。

     java訪問-----JDBC程序-----oracle數據庫

     java訪問------JDBC 程序------mysql數據庫

     java訪問------JDBC 程序--------db2數據庫


以下簡介JDBC針對oracl和mysql數據庫。

oracle提供的jdbc接口的實現類-------ojdbc5.jar------jdk5.0  ojdbc6.jar-----jdk6.0

mysql提供的jdbc接口實現類--------mysql-connector-java-6.0.6

如果要開發JDBC程序,必然少不了這些jar包。下載可以去官網

https://dev.mysql.com/downloads/connector/


JDBC常用API簡介:

java.sql.Connection:代表一個數據庫連接;

java.sql.Statement:發送sql語句1至數據庫;(發送sql的工具)

DriverManager:(類) 管理多個數據庫驅動類

java.sql.ResultSet:結果集,存放查詢語句執行後返回的數據結果


下圖1.0爲JDBC訪問數據庫流程


                                                圖1.0




wKioL1kJpZiRcTLuAABf3RtUVgo897.png-wh_50



JDBC開發步驟

1: 加載驅動

如果是oracle數據庫:

將oracle ojdbc.jar 複製到項目裏,點擊項目,右鍵build path --add to buidpath 

Class.forName("oracle.jdbc.OracleDriver");

如果是mysql數據庫:

將mysql  mysql-connector-java-6.0.6-bin 複製到項目裏,build path --add to buidpath 

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

2:連接數據庫

     user:root----數據庫用戶名

     password:root------數據庫密碼

     url: oracle ----協議 :子協議 :thin:@ip:端口:SID(SID數據庫的實例名)。

     eg:String url = "jdbc:oracle:thin:@localhost:1521:XE";

     url:mysql ------ 協議:子協議://ip:端口:數據庫名

   eg:String url = "jdbc:mysql://localhost:3306/zdx";


3:準備sql

     sql字符串中不能有分號;

4:Statement將sql發送至數據庫

      int i=  executeUpdate(sql); //返回受影響的行數

5:如果是查詢語句,返回結果集,處理ResultSet。

6:關閉連接,釋放資源,按照先打開後關閉的原則。


以上6步驟時開發JDBC程序的標準步驟。


ResultSet結果集簡介及使用方法:

     ResultSet結果集:存放查詢結果數據。

     ResultSet rs = Statement.executeQuery();

     rs指針初始位置在第一行數據之前

     boolean rs.next(): ,

     將rs的指針向下移動一位,當前行無數據返回false,有數據返回true,並獲得查詢數據。

     提供一組getXXX(int列序號或String列名)方法用於取得數據


以上是JDBC簡介,下面是JDBC例子,例子纔是王道。

JDBC1.0版本------是1.0版本。後面還會有更優秀的版本娓娓道來!


JDBC_ResultSet.java

public class JDBC_ResultSet {

       public static void main(String[] args) throws ClassNotFoundException, SQLException {

             //1:加載驅動

             //Class.forName("oracle.jdbc.OracleDriver");

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

             //2:獲得數據庫連接

             String user = "root";

             String password = "root";

             //String url = "jdbc:oracle:thin:@localhost:1521:XE";

             String url = "jdbc:mysql://localhost:3306/zdx?serverTimezone=UTC";

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

             //3:準備sql

             String sql = "select * from student";

             //4:創建Statement,發送sql

             Statement stm = conn.createStatement();//獲的statement對象

             //5:如果是查詢,處理結果集

             ResultSet rs = stm.executeQuery(sql);

             while(rs.next()){

                    int id = rs.getInt(1);

                    String name = rs.getString(2);

                    int age = rs.getInt(3);

                    String phone = rs.getString(4);

                    System.out.println(id+"---"+name+"---"+age+"---"+phone);

             }

             //6:關閉連接,釋放資源,原則,先打開後關閉

             stm.close();

             conn.close();

             

       }

}



到了此處,我們的JDBC1.0已經寫完了,但是爲什麼說是1.0呢,因爲這個版本有一個很大的漏洞。

沒錯,那就是——依賴注入問題。

===================華麗麗的分割線==============================

下面我們可以看這個例子


JDBC_Statement.java


public class JDBC_Statement {

       public static void main(String[] args) throws Exception {

             

             Scanner sc = new Scanner(System.in);

             System.out.println("請輸入卡號");

             String card_id = sc.nextLine();

             System.out.println("請輸入密碼");

             String pwd = sc.nextLine();

             //1:加載驅動

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

             //2:獲得數據庫連接

             String user = "root";

             String password = "root";

             String url = "jdbc:mysql://localhost:3306/zdx?serverTimezone=UTC";

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

             //3:準備sql

             String sql = "select * from account where card_id ="+card_id

                                 +" and password = '"+pwd+"'";

             System.out.println(sql);

             //4:創建Statement,發送sql

             Statement stm = conn.createStatement();//獲的statement對象

             //5:如果是查詢,處理結果集

             ResultSet rs = stm.executeQuery(sql);

             if(rs.next()){

                    System.out.println("可以取錢了");

             }else{

                    System.out.println("密碼賬戶不正確");

             }

             //6:關閉連接,釋放資源,原則,先打開後關閉

             stm.close();

             conn.close();

       }

}



這是一個銀行取錢的例子,如代碼所寫。

數據庫有這樣一張account表,數據和字段如下:


wKiom1kJpZWTbWdWAABOlaj65Kc161.png-wh_50

現在在控制檯輸入卡號密碼,卡號密碼正確即可取錢,

錯誤即提示賬戶不正確。


現在控制檯輸入正確卡號密碼


wKioL1kJpZiCmr-kAAAVJsT6_58217.png-wh_50

然後,我輸入錯誤的卡號密碼竟然也可以取錢!輸入錯誤的卡號 “123 or 1=1 -- ”密碼 "zxc"結果如下

wKioL1kJpZaQzqTnAAAWVC1hM0c830.png-wh_50


可見依然能訪問數據庫,這對於銀行可是致命性錯誤,密碼錯誤還可以取錢。

這就是依賴注入引起的著名錯誤。

依靠人爲輸入破壞sql結構.

select * from account where id = 1001 or 1=1 -- and password = 'xxx'

這條sql裏,其中--是sql裏的註釋 or 1=1 永遠爲真並且還是or連接,

所以這條sql只執行到 or 1=1 ,1=1又是恆等。所以跳過了密碼。


爲了解決這個問題,我們就要說PreparedStatement!


PreparedStatement簡介及使用


PreparedStatement構建動態SQL,通過PreparedStatement執行SQL語句,解決注入***。

PreparedStatement是Statement的子接口。

通過連接創建PreparedStatement,創建時將SQL語句中發生變化的部分用佔位符“?“ 代替。

功能:和statement一樣,發送sql語句。 

          但是執行多個同構sql效率高。同構sql能省去①②③步驟。

使用步驟:

     1.創建pstm

     String sql = "select * from account where card_id = ? and password = ?"

     PreparedStateement pstm = conn.prepareStatement(sql);

          ①驗證權限

          ②驗證語法

          ③將sql轉換內部指令

2.綁定參數

     pstm.setInt(1,值);

     pstm.setString(2,值);

3.發送綁定參數至DB數據庫

     pstm.executeUpdate();//曾刪改

     pstm.executedQuery();//查詢

          ④執行內部指令操作數據庫

mysql內部執行sql步驟:

          ①驗證權限

          ②驗證語法

          ③將sql轉換內部指令

          ④執行內部指令操作數據庫

使用PareparedStatement解決注入***問題後的代碼如下:

JDBC2.0版本 是2.0版本>_< 。後面還會有更優秀的版本娓娓道來!

JDBC_PreparedStatement.java


public class JDBC_PreparedStatement {

       public static void main(String[] args) throws Exception {

             

             Scanner sc = new Scanner(System.in);

             System.out.println("請輸入卡號");

             String card_id = sc.nextLine();

             System.out.println("請輸入密碼");

             String pwd = sc.nextLine();

             //1:加載驅動

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

             //2:獲得數據庫連接

             String user = "root";

             String password = "root";

             String url = "jdbc:mysql://localhost:3306/zdx?serverTimezone=UTC";

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

             //3:準備sql

             String sql = "select * from account where card_id =? and password =?";

             PreparedStatement pstm = conn.prepareStatement(sql);

             pstm.setInt(1, Integer.valueOf(card_id));

             pstm.setString(2, pwd);

             //5:如果是查詢,處理結果集

             ResultSet rs = pstm.executeQuery();

             if(rs.next()){

                    System.out.println("可以取錢了");

             }else{

                    System.out.println("密碼賬戶不正確");

             }

             //6:關閉連接,釋放資源,原則,先打開後關閉

             rs.close();

             pstm.close();

             conn.close();

       }

}

現在用PreparedStatement程序執行,輸入卡號,密碼


wKiom1kJpZeS0tSsAAAJ4VHTEYo498.png-wh_50


出現異常,不會再出現密碼錯誤卻取錢的問題了!!!


總結對比一下 Statement 和PreparedStatement




Statement

PreparedStatement

關係

父接口

子接口

安全

存在注入隱患

解決sql注入

效率

執行異構sql快

執行同構sql快


至此JDBC2.0結束。JDBC基本內容結束,以下是JDBC進階內容。和優化版JDBC例子。


=====================華麗麗的分割線===========================


由於 篇幅有限,後續部分請參閱下篇博客。由淺到深學習JDBC二

不妥之處懇請讀者批評指正,共同進步。

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