JDBC學習-JDBC入門

JDCB概念

Java Database Connectivity,數據庫連接。
何謂JDBC,我們要使用java語言來操作數據庫,然 數據庫有很多種,每種的規則可能都有區別,不可能針對特有的數據庫來針對操作,效率太低,所以這裏sun公司定義了一套操作所有關係型數據庫的接口。讓所有的數據庫來爲這個接口創建實現類,(實現類就是數據庫驅動)。所以,java程序員只需要使用JDBC來編程即可,不用再管數據庫的特性。這裏的思想其實跟之前的JVM很像,用同一的java語言來運行在不同的OS上,從而達到可移植性。可見java語言一直都在遵循這個理念。
總而言之。其實是官方(sun)定義的一套操作所有關係型數據庫的規則–接口。各個數據庫廠商去實現這套接口,提供數據庫驅動jar包。我們可以使用這套接口jdbc來編程,真正執行的代碼是驅動jar包中的實現類。JDBC是溝通代碼與數據庫的橋樑

使用步驟

//        1.導入驅動jar包
//        2.註冊驅動
        Class.forName("com.mysql.jdbc.Driver");
//        獲取數據庫連接對象
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1", "root", "root");
//       定義sql語句
        String sql = " UPDATE student SET age = 20;";
//       獲取執行sql的對象statement
        Statement stmt = conn.createStatement();
//        執行sql
        int count = stmt.executeUpdate(sql);
//        處理結果
        System.out.println(count);
        stmt.close();
        conn.close();

  1. 導入驅動jar包
    因爲上面我們也說到JDBC是一套接口嘛,也不知道你具體使用的是哪個數據庫,所以這裏需要手動導入你所用的數據庫的jar包(驅動)。把jar包放到目錄的附近,把路徑添加進去。這裏不做贅述。其中可能會遇到一些問題,可以見我的另外一篇博客。
  2. 註冊驅動
    這一步是爲了讓程序知道我們的驅動。這裏用到了forName()方法,該方法返回傳參字符串名稱的類或接口對象,也就是輸入類名或接口名,返回對象。我們這裏傳入的是JDBC實現類(驅動類),它會返回一個對象,明顯這裏沒有接收對象,因爲我們需要的是註冊驅動,而不是這個驅動類對象。在Driver類的源碼中,存在着靜態代碼塊,衆所周知,靜態代碼塊隨着類的加載而執行,只執行一次。在此類的靜態代碼塊中,有這樣的java語句:java.sql.DriverManager.registerDriver(new Driver())};即註冊驅動。
  3. 獲取數據庫的連接對象
    上面的代碼是通過DriverManage的靜態方法getConnectio()來獲得的,其實在實際使用過程中,這種方法比較低效,一般採用從數據庫連接池中獲取連接對象的方式。(就像多線程過程中,我們通過線程池獲取線程一樣)。數據庫連接池我們下面再講。
    連接對象需要傳入數據庫的ip地址,端口,還有用戶名與密碼,用以連接。其實說是連接,這裏不妨將其認作成數據庫的登錄操作。登錄的時候,我們需要進入登錄頁面,然後啪啪啪輸入我們的賬號信息。
    這裏需要注意第一個傳參,除了ip和端口,形式固定,切勿寫錯,否則報錯。
  4. 定義SQL語句
    我們這裏定義SQL語句是用字符串的形式,這裏其實有兩種SQL語句。一種是上面這種全是字符串,叫做靜態SQL語句,一般是不使用的,因爲存在SQL注入安全問題,且效率不高;還有一種就是預編譯SQL,一般用這個,效率高,我們下面會詳細講。
  5. 獲取執行SQL語句的對象statement
    我們從連接對象那裏獲得操作對象Statement。
  6. 執行SQL,獲取返回結果
    利用我們的操作對象,把要執行的SQL語句放進去,然後就會得到返回結果。
  7. 處理返回結果
    返回結果各式各樣,有它固定的形式。
    如果是查詢操作,結果是一個結果集ResultSet,這個結果集像是一個表格一樣的東西,我們還得對這個表格進行處理。結果集我們下面介紹。
    而如果是更新操作,結果是更新的行數,我們可以通過這個行數來判斷是否更新成功,或是更新的情況。
  8. 釋放資源
    要養成好的習慣,對於這裏釋放資源,如果是穿件的連接對象,會直接釋放;如果是從數據庫連接池中獲取的數據庫連接對象,則會返回數據庫連接池。代碼一樣,無需改變,這裏妙極了。

這裏各個對象的獲取都是層層遞進的,從DriverManage那裏輸入數據庫信息,獲取連接對象,再從連接對象那裏獲取執行對象Statement,之後往執行對象中傳入SQL語句進而執行。

JDBC相關接口

Connection
數據庫的連接對象,有了這個連接對象,說明已經連接上了數據庫。這個類有很多的方法,我們暫時一開始接觸的只有CreateStatement()方法(獲取數據庫執行對象)與事務的提交,回滾,等相關的方法。具體的看api即可

Statement
此類是執行靜態SQL,其實基本不用使用這個

ResultSet
結果集,其中封裝着查詢的結果。
我們可以把查詢的結果看成是下圖
在這裏插入圖片描述
一張表,對,就是一張表。查詢的結果可不就是一張表嘛。如何對這張表進行處理呢,我們要獲取比如第二行第一個數據lisa怎麼獲得呢。
這裏要有一個概念,就是遊標,或者你可以理解成光標。一開始我們的光標是指在第一行的,第一行沒有數據,它是表頭。
如果我們要讀取第二行第一數據,我們是不是得把光標往下移一個,這裏我們使用ResultSet中的next()方法,光標向下移動一行,它的返回值是boolean類型,如果當前行是最後一行末尾,放回false,不是就返回true。
然後到達了第二行之後,我們需要後去第一個數據,這裏有get類型(參數1,參數2)方法,參數1是int類型,代表列的編號,而參數2是列名。通過這個方法,我們可以獲取第二行第一個數據。代碼如下

//        向下移動一行
        rs.next();
//        選擇第一個 這裏計數是從1起的
        rs.getString(1);

PreparedStatement
這個與Statement類似,但是處理預編譯SQL的。
具體的使用比較簡單,只是與Statement有些區別。
首先我們使用的SQL語句不再是靜態的,而是預編譯的,其中採用?爲佔位符,在獲取執行對象PreparedStatement時就把SQL語句傳入,之後呢便是給?賦值,再然後是執行SQL,(因爲先前已經傳如了SQL,這裏便不需要再傳入SQL語句),這裏便是PreparedStatement與Statement在使用上的區別。

靜態SQL與預編譯SQL

靜態SQL,像我們上面代碼示例那樣就是靜態SQL,同時,下面的例子也是靜態SQL

String sql = "select* from user where username = '"+username+"' and password = '"+password+"'";
            //獲取執行sql的對象
 stmt = conn.createStatement();
            //執行查詢
 rs = stmt.executeQuery(sql);

,這種由字符串拼接而成的都是靜態SQL,雖然其中包含着變量,但也是靜態SQL。
在網上所有查詢靜態SQL與預編譯SQL,基本都是說靜態SQL在編譯期就已經確定,而預編譯需要到運行時才能確定SQL語句。
在API文檔中關於Statement的敘述中寫道:用於執行靜態SQL語句並返回其生成的結果的對象,在PreparedStatement的敘述中寫道:用於執行預編譯SQL語句。
而在上面的例子中,明顯在編譯期是不能確定SQL語句的,因爲其中是有變量的,只有到運行時才能確定,所以我在這糾結了好久,也得不到什麼答案。可能這個編譯並不適用於這裏的JABC。
但這裏我們可以這樣理解區別,結合PreparedStatement對象使用預編譯SQL語句來看看:

 String sql = "select * from user where username = ? and password = ?";
            PreparedStatement pstmt = conn.prepareStatement(sql);
            pstmt.setString(1,"root");
            pstmt.setString(2,"root");
            pstmt.executeQuery();
            

通過兩段代碼可以看到明顯的區別:

  • 首先在於SQL語句上,靜態SQL語句的是採用字符串拼接,而動態SQL語句是一條完整的字符串,沒有拼接;在靜態SQL語句中有着變量,而動態SQL語句中是用?來作爲佔位符。
  • 因爲靜態SQL語句是字符串拼接,其中包含變量,變量是本身就有值的,而預編譯SQL語句是有佔位符的,需要之後再調用setXxx來定義值。
  • 在靜態SQL語句的執行上,是先通過連接對象獲得Statement對象,之後在執行時纔會把SQL語句傳入;而預編譯SQL語句是在通過連接對象獲取PreparedStatement時就傳入了SQL語句,之後再確定其中的值(即確定全部SQL語句),然後在執行時不用再傳入SQL語句

靜態SQL語句在傳入Statement時已經是確定的,而在預編譯SQL語句傳入PreparedStatement時是沒有確定的,之後還可以確定。
除了這個,靜態SQL語句存在的問題是有的,比如上面代碼示例,可能用戶輸入SQL語句關鍵字,就會導致SQL語句偏離程序員的意圖,變得不可控(老生常談的登錄問題,輸入or 1=1 會使得條件永遠爲真),而預編譯SQL語句是不存在這個問題的,因爲佔位符那裏這能輸入參數,關鍵字是無效的,因爲這裏從靜態SQL直接嵌入語句編程了傳參進入語句。
在靜態SQL與預編譯SQL的速度上,我用林信良所寫的《java學習筆記》中的一段話來說明:在驅動程序支持的情況下,使用PreparedStatement,可以將SQL描述與編譯爲數據庫的執行命令。由於已經是數據庫的可執行指令,執行速度會快很多,而使用Statement對象,是在執行時將SQL直接送到數據庫,由數據庫做剖析、直譯再執行,速度就慢很多

數據庫連接池

爲什麼要使用數據庫連接池?
存放數據庫連接的容器,當系統初始化之後,容器被創建,容器中會申請一些連接對象,當用戶來訪問數據庫時,從容器中獲取連接對象,用戶訪問完之後,會講連接對象歸還給容器。
這裏數據庫連接池其實就跟我們的多線程連接池一個道理。
與JDBC一樣,數據庫連接池也是SUN公司定義的接口DataSource,由數據庫廠商來實現,具體使用也要導入jar包,具體使用不贅述。

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