Java基礎教程:JDBC編程

Java基礎教程:JDBC編程

一、什麼是JDBC

  JDBC 指 Java 數據庫鏈接,是一種標準Java應用編程接口( JAVA API),用來鏈接 Java 編程語言和普遍的數據庫html

  JDBC API 庫包含下面提到的每一個任務,都是與數據庫相關的經常使用用法。java

  • 製做到數據庫的鏈接。
  • 建立 SQL 或 MySQL 語句。
  • 執行 SQL 或 MySQL 查詢數據庫。
  • 查看和修改所產生的記錄。

  從根本上來講,JDBC 是一種規範,它提供了一套完整的接口,容許便攜式訪問到底層數據庫,所以能夠用 Java 編寫不一樣類型的可執行文件,例如:mysql

  • Java 應用程序
  • Java Applets
  • Java Servlets
  • Java ServerPages (JSPs)
  • Enterprise JavaBeans (EJBs)

  全部這些不一樣的可執行文件就可使用 JDBC 驅動程序來訪問數據庫,這樣能夠方便的訪問數據。JDBC 具備 ODBC 同樣的性能,容許 Java 程序包含與數據庫無關的代碼。sql

 二、JDBC架構

    

  • JDBC API: 提供了應用程序對 JDBC 管理器的鏈接。數據庫

  • JDBC Driver API: 提供了 JDBC 管理器對驅動程序鏈接。
  • JDBC 驅動程序管理器可確保正確的驅動程序來訪問每一個數據源。該驅動程序管理器可以支持鏈接到多個異構數據庫的多個併發的驅動程序

三、常見的JDBC組件

  以下所示爲JDBC開發中主要用到的類。編程

  • DriverManager :這個類管理一系列數據庫驅動程序。匹配鏈接使用通訊子協議從 JAVA 應用程序中請求合適的數據庫驅動程序。識別 JDBC 下某個子協議的第一驅動程序將被用於創建數據庫鏈接。
  • Driver : 這個接口處理與數據庫服務器的通訊。你將不多直接與驅動程序互動。相反,你使用 DriverManager 中的對象,它管理此類型的對象。它也抽象與驅動程序對象工做相關的詳細信息。
  • Connection此接口具備接觸數據庫的全部方法。該鏈接對象表示通訊上下文,即,全部與數據庫的通訊僅經過這個鏈接對象進行。
  • Statement使用建立於這個接口的對象將 SQL 語句提交到數據庫。除了執行存儲過程之外,一些派生的接口也接受參數
  • ResultSet在你使用語句對象執行 SQL 查詢後,這些對象保存從數據得到的數據。它做爲一個迭代器,讓您能夠經過它的數據來移動。
  • SQLException這個類處理髮生在數據庫應用程序的任何錯誤

四、開發流程

1.下載JDBC-MySQL官方驅動

  

2.將JDBC驅動加入到環境變量中

  

 

3.示例代碼

package com.company;
//第一步:導入必須的包
import java.sql.*;

public class Main {
    //第二步:說明JDBC驅動的名稱和數據庫的地址
    static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
    static final String DB_URL = "jdbc:mysql://localhost:3306/test";

    //第三步:說明數據庫的認證帳戶及密碼
    static final String USER = "root";
    static final String PASS = "123456";

    public static void main(String[] args) {
        //第四步:註冊JDBC驅動
        try {
            Class.forName(JDBC_DRIVER);
        } catch (ClassNotFoundException e) {
            //這裏會發生類沒有找到的異常!
            e.printStackTrace();
        }
        //第五步:得到數據庫鏈接
        try {
            Connection connection =  DriverManager.getConnection(DB_URL,USER,PASS);
            //第六步:執行查詢語句
            Statement statement = connection.createStatement();
            String sql = "SELECT * FROM crawler_article";
            ResultSet rs =statement.executeQuery(sql);
            while (rs.next())
            {
                String title = rs.getString("title");
                String author = rs.getString("author");
                System.out.println(title+":"+author);
            }
            //第七步:關閉鏈接資源
            rs.close();
            statement.close();
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
            //這裏會發生SQL異常,由於咱們提供的的帳戶和密碼不必定能鏈接成功
        }
    }
}

五、進階內容

數據類型

Java數據類型與SQL數據類型的轉換:數組

  

結果集

  SQL 語句從數據庫查詢中獲取數據,並將數據返回到結果集中。SELECT 語句是一種標準的方法,它從一個數據庫中選擇行記錄,並顯示在一個結果集中。 java.sql.ResultSet 接口表示一個數據庫查詢的結果集。一個 ResultSet 對象控制一個光標指向當前行的結果集。術語「結果集」是指包含在 ResultSet 對象中的行和列的數據。服務器

ResultSet 接口的方法可細分爲三類-架構

  • 導航方法:用於移動光標。
  • 獲取方法:用於查看當前行被光標所指向的列中的數據。
  • 更新方法:用於更新當前行的列中的數據。這些更新也會更新數據庫中的數據。

光標的移動基於 ResultSet 的屬性。用相應的語句生成 ResultSet 對象時,同時生成 ResultSet 的屬性。併發

JDBC 提供了鏈接方法經過下列建立語句來生成你所需的 ResultSet 對象:

  • createStatement(int RSType, int RSConcurrency);
  • prepareStatement(String SQL, int RSType, int RSConcurrency);
  • prepareCall(String sql, int RSType, int RSConcurrency);

第一個參數表示 ResultSet 對象的類型,第二個參數是兩個 ResultSet 常量之一,該常量用於判斷該結果集是隻讀的仍是可修改的。

導航結果集

在 ResultSet 接口中包括以下幾種方法涉及移動光標-

  

ResultSet接口中含有幾十種從當前行獲取數據的方法。
查看結果集

每一個可能的數據類型都有一個 get 方法,而且每一個 get 方法有兩個版本-

  • 一個須要列名。
  • 一個須要列的索引。

例如,若是你想查看的列包含一個 int 類型,你須要在 ResultSet 中調用 getInt()方法-

S.N. 方法 & 描述
1 public int getInt(String columnName) throws SQLException

返回當前行中名爲 columnName 的列的 int 值。

2 public int getInt(int columnIndex) throws SQLException

返回當前行中指定列的索引的 int 值。列索引從 1 開始,意味着行中的第一列是 1 ,第二列是 2 ,以此類推。

一樣的,在 ResultSet 接口中還有獲取八個 Java 原始類型的 get 方法,以及常見的類型,好比 java.lang.String,java.lang.Object 和 java.net.URL。

也有用於獲取 SQL 數據類型 java.sql.Date, java.sql.Time, java.sql.Timestamp, java.sql.Clob,java.sql.Blob 中的方法。查看文檔能夠了解使用這些 SQL 數據類型的更多的信息。

更新的結果集

ResultSet 接口包含了一系列的更新方法,該方法用於更新結果集中的數據。

用 get 方法能夠有兩個更新方法來更新任一數據類型-

  • 一個須要列名。
  • 一個須要列的索引。

例如,要更新一個結果集的當前行的 String 列,你可使用任一以下所示的 updateString()方法-

S.N. 方法 & 描述
1 public void updateString(int columnIndex, String s) throws SQLException

將指定列的字符串的值改成 s。

2 public void updateString(String columnName, String s) throws SQLException

相似於前面的方法,不一樣之處在於指定的列是用名字來指定的,而不是它的索引。

八個原始數據類型都有其更新方法,好比 String,Object,URL,和在 java.sql 包中的 SQL 數據類型。

更新結果集中的行將改變當前行的列中的 ResultSet 對象,而不是基礎數據庫中的數據。要更新數據庫中一行的數據,你須要調用如下的任一方法-

S.N. 方法 & 描述
1 public void updateRow()

經過更新數據庫中相對應的行來更新當前行。

2 public void deleteRow()

從數據庫中刪除當前行。

3 public void refreshRow()

在結果集中刷新數據,以反映數據庫中最新的數據變化。

4 public void cancelRowUpdates()

取消對當前行的任何修改。

5 public void insertRow()

在數據庫中插入一行。本方法只有在光標指向插入行的時候才能被調用。

事物

  若是你的 JDBC 鏈接是處於自動提交模式下,該模式爲默認模式,那麼每句 SQL 語句都是在其完成時提交到數據庫。

對簡單的應用程序來講這種模式至關好,但有三個緣由你可能想關閉自動提交模式,並管理你本身的事務-

  • 爲了提升性能
  • 爲了保持業務流程的完整性
  • 使用分佈式事務

  你能夠經過事務在任意時間來控制以及更改應用到數據庫。它把單個 SQL 語句或一組 SQL 語句做爲一個邏輯單元,若是其中任一語句失敗,則整個事務失敗。

若要啓用手動事務模式來代替 JDBC 驅動程序默認使用的自動提交模式的話,使用 Connection 對象的的 setAutoCommit()方法。若是傳遞一個布爾值 false 到 setAutoCommit()方法,你就關閉自動提交模式。你也能夠傳遞一個布爾值 true 將其再次打開。

例如,若是有一個名爲 conn 的 Connection 對象,如下的代碼將關閉自動提交模式-

conn.setAutoCommit(false);

提交和回滾

當你完成了你的修改,而且要提交你的修改,能夠在 connection 對象裏調用 commit()方法,以下所示-

conn.commit( );

另外,用名爲 conn 的鏈接回滾數據到數據庫,使用以下所示的代碼-

conn.rollback( );

下面的例子說明了如何使用提交和回滾對象-

try{
   //Assume a valid connection object conn
   conn.setAutoCommit(false);
   Statement stmt = conn.createStatement();

   String SQL = "INSERT INTO Employees  " +
                "VALUES (106, 20, 'Rita', 'Tez')";
   stmt.executeUpdate(SQL);  
   //Submit a malformed SQL statement that breaks
   String SQL = "INSERTED IN Employees  " +
                "VALUES (107, 22, 'Sita', 'Singh')";
   stmt.executeUpdate(SQL);
   // If there is no error.
   conn.commit();
}catch(SQLException se){
   // If there is any error.
   conn.rollback();
}

在這種狀況下,以前的 INSERT 語句不會成功,一切都將被回滾到最初狀態。

使用還原點

  新的 JDBC 3.0 還原點接口提供了額外的事務控制。大部分現代的數據庫管理系統的環境都支持設定還原點,例如 Oracle 的 PL/SQL。

當你在事務中設置一個還原點來定義一個邏輯回滾點。若是在一個還原點以後發生錯誤,那麼可使用 rollback 方法來撤消全部的修改或在該還原點以後所作的修改。

Connection 對象有兩個新的方法來管理還原點-

  • setSavepoint(String savepointName): 定義了一個新的還原點。它也返回一個 Savepoint 對象。

  • releaseSavepoint(Savepoint savepointName): 刪除一個還原點。請注意,它須要一個做爲參數的 Savepoint 對象。這個對象一般是由 setSavepoint() 方法生成的一個還原點。

  有一個 rollback (String savepointName) 方法,該方法能夠回滾到指定的還原點。

  下面的例子說明了如何使用 Savepoint 對象-

try{
   //Assume a valid connection object conn
   conn.setAutoCommit(false);
   Statement stmt = conn.createStatement();

   //set a Savepoint
   Savepoint savepoint1 = conn.setSavepoint("Savepoint1");
   String SQL = "INSERT INTO Employees " +
                "VALUES (106, 20, 'Rita', 'Tez')";
   stmt.executeUpdate(SQL);  
   //Submit a malformed SQL statement that breaks
   String SQL = "INSERTED IN Employees " +
                "VALUES (107, 22, 'Sita', 'Tez')";
   stmt.executeUpdate(SQL);
   // If there is no error, commit the changes.
   conn.commit();

}catch(SQLException se){
   // If there is any error.
   conn.rollback(savepoint1);
}

在這種狀況下,以前的 INSERT 語句不會成功,一切都將被回滾到最初狀態。

批處理

  批處理是指你將關聯的 SQL 語句組合成一個批處理,並將他們當成一個調用提交給數據庫。

  當你一次發送多個 SQL 語句到數據庫時,能夠減小通訊的資源消耗,從而提升了性能。

  • JDBC 驅動程序不必定支持該功能。你可使用 DatabaseMetaData.supportsBatchUpdates() 方法來肯定目標數據庫是否支持批處理更新。若是你的JDBC驅動程序支持此功能,則該方法返回值爲 true。

  • Statement,PreparedStatement 和 CallableStatement 的 addBatch() 方法用於添加單個語句到批處理。

  • executeBatch() 方法用於啓動執行全部組合在一塊兒的語句。

  • executeBatch() 方法返回一個整數數組,數組中的每一個元素表明了各自的更新語句的更新數目。

  • 正如你能夠添加語句到批處理中,你也能夠用 clearBatch() 方法刪除它們。此方法刪除全部用 addBatch() 方法添加的語句。可是,你不能有選擇性地選擇要刪除的語句。

批處理和 Statement 對象

使用 Statement 對象來使用批處理所須要的典型步驟以下所示-

  • 使用 createStatement() 方法建立一個 Statement 對象。
  • 使用 setAutoCommit() 方法將自動提交設爲 false。
  • 被建立的 Statement 對象可使用 addBatch() 方法來添加你想要的全部SQL語句。
  • 被建立的 Statement 對象能夠用 executeBatch() 將全部的 SQL 語句執行。
  • 最後,使用 commit() 方法提交全部的更改。

示例

下面的代碼段提供了一個使用 Statement 對象批量更新的例子-

// Create statement object
Statement stmt = conn.createStatement();

// Set auto-commit to false
conn.setAutoCommit(false);

// Create SQL statement
String SQL = "INSERT INTO Employees (id, first, last, age) " +
             "VALUES(200,'Zia', 'Ali', 30)";
// Add above SQL statement in the batch.
stmt.addBatch(SQL);

// Create one more SQL statement
String SQL = "INSERT INTO Employees (id, first, last, age) " +
             "VALUES(201,'Raj', 'Kumar', 35)";
// Add above SQL statement in the batch.
stmt.addBatch(SQL);

// Create one more SQL statement
String SQL = "UPDATE Employees SET age = 35 " +
             "WHERE id = 100";
// Add above SQL statement in the batch.
stmt.addBatch(SQL);

// Create an int[] to hold returned values
int[] count = stmt.executeBatch();

//Explicitly commit statements to apply changes
conn.commit();

批處理和 PrepareStatement 對象

使用 prepareStatement 對象來使用批處理須要的典型步驟以下所示-

  • 使用佔位符建立 SQL 語句。
  • 使用任一 prepareStatement() 方法建立 prepareStatement 對象。
  • 使用 setAutoCommit() 方法將自動提交設爲 false。
  • 被建立的 Statement 對象可使用 addBatch() 方法來添加你想要的全部 SQL 語句。
  • 被建立的 Statement 對象能夠用 executeBatch() 將全部的 SQL 語句執行。
  • 最後,使用 commit() 方法提交全部的更改。

下面的代碼段提供了一個使用 PrepareStatement 對象批量更新的示例-

// Create SQL statement
String SQL = "INSERT INTO Employees (id, first, last, age) " +
             "VALUES(?, ?, ?, ?)";

// Create PrepareStatement object
PreparedStatemen pstmt = conn.prepareStatement(SQL);

//Set auto-commit to false
conn.setAutoCommit(false);

// Set the variables
pstmt.setInt( 1, 400 );
pstmt.setString( 2, "Pappu" );
pstmt.setString( 3, "Singh" );
pstmt.setInt( 4, 33 );
// Add it to the batch
pstmt.addBatch();

// Set the variables
pstmt.setInt( 1, 401 );
pstmt.setString( 2, "Pawan" );
pstmt.setString( 3, "Singh" );
pstmt.setInt( 4, 31 );
// Add it to the batch
pstmt.addBatch();

//add more batches
.
.
.
.
//Create an int[] to hold returned values
int[] count = stmt.executeBatch();

//Explicitly commit statements to apply changes
conn.commit();

存儲過程

建立 CallableStatement 對象

假設,你須要執行下面的 Oracle 存儲過程-

CREATE OR REPLACE PROCEDURE getEmpName 
   (EMP_ID IN NUMBER, EMP_FIRST OUT VARCHAR) AS
BEGIN
   SELECT first INTO EMP_FIRST
   FROM Employees
   WHERE ID = EMP_ID;
END;

注意:上面的存儲過程是在 Oracle 使用的,但咱們使用的是 MySQL 數據庫,因此咱們在 MySQL 的環境下須要從新寫出相同功能的代碼,下面的代碼是在 EMP 數據庫中建立相同功能的代碼-

DELIMITER $$

DROP PROCEDURE IF EXISTS `EMP`.`getEmpName` $$
CREATE PROCEDURE `EMP`.`getEmpName` 
   (IN EMP_ID INT, OUT EMP_FIRST VARCHAR(255))
BEGIN
   SELECT first INTO EMP_FIRST
   FROM Employees
   WHERE ID = EMP_ID;
END $$

DELIMITER ;

當前有三種類型的參數:IN,OUT 和 INOUT。PreparedStatement 對象只能使用 IN 參數。CallableStatement 對象可使用全部的三種類型。

下面是三種類型參數的定義

CallableStatement cstmt = null;下面的代碼片斷展現瞭如何使用 Connection.prepareCall() 方法實現一個基於上述存儲過程的 CallableStatement 對象-

try {
   String SQL = "{call getEmpName (?, ?)}";
   cstmt = conn.prepareCall (SQL);
   . . .
}
catch (SQLException e) {
   . . .
}
finally {
   . . .
}

字符串變量 SQL 使用參數佔位符來表示存儲過程。

使用 CallableStatement 對象就像使用 PreparedStatement 對象。在執行該語句前,你必須將值綁定到全部的參數,不然你將收到一個 SQL 異常。

若是你有 IN 參數,只要按照適用於 PreparedStatement 對象相同的規則和技巧;用 setXXX()方法來綁定對應的 Java 數據類型。

當你使用 OUT 和 INOUT 參數就必須採用額外的 CallableStatement 方法:registerOutParameter()。registerOutParameter() 方法將 JDBC 數據類型綁定到存儲過程返回的數據類型。

一旦你調用了存儲過程,你能夠用適當的 getXXX()方法從 OUT 參數參數中檢索數值。這種方法將檢索出來的 SQL 類型的值映射到 Java 數據類型。

關閉 CallableStatement 對象

正如你關閉其它的 Statement 對象,出於一樣的緣由,你也應該關閉 CallableStatement 對象。

close()方法簡單的調用就能夠完成這項工做。若是你先關閉了 Connection 對象,那麼它也會關閉 CallableStatement 對象。然而,你應該始終明確關閉 CallableStatement 對象,以確保該對象被完全關閉。

CallableStatement cstmt = null;
try {
   String SQL = "{call getEmpName (?, ?)}";
   cstmt = conn.prepareCall (SQL);
   . . .
}
catch (SQLException e) {
   . . .
}
finally {
   cstmt.close();
}

流數據

PreparedStatement 對象必須具有使用輸入和輸出流來提供參數數據的能力。這使你可以將整個文件存儲到數據庫列中,這樣數據庫就能存儲大型數據,例如 CLOB 和 BLOB 數據類型。

用於流數據有下列幾種方法-

  • setAsciiStream(): 該方法是用來提供較大的 ASCII 值。
  • setCharacterStream(): 該方法是用來提供較大的 UNICODE 值。
  • setBinaryStream(): 該方法是用來提供較大的二進制值。

setXXXStream()方法須要一個額外的參數,該參數是除了參數佔位符的文件大小。這個參數通知驅動程序經過使用流有多少數據被髮送到數據庫中。

示例

假如咱們到要上傳一個名爲 XML_Data.xml 的 XML 文件到數據庫的表中。下面是該 XML 文件的內容-

<?xml version="1.0"?>
<Employee>
<id>100</id>
<first>Zara</first>
<last>Ali</last>
<Salary>10000</Salary>
<Dob>18-08-1978</Dob>
<Employee>

將該 XML 文件和你要運行的示例保存在相同的目錄的。

這個示例將建立一個數據庫表 XML_Data ,而後 XML_Data.xml 將被上傳到該表中。

將下面的示例拷貝並粘帖到 JDBCExample.java 中,編譯並運行它,以下所示-

// Import required packages
import java.sql.*;
import java.io.*;
import java.util.*;

public class JDBCExample {
   // JDBC driver name and database URL
   static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";  
   static final String DB_URL = "jdbc:mysql://localhost/EMP";

   //  Database credentials
   static final String USER = "username";
   static final String PASS = "password";

   public static void main(String[] args) {
   Connection conn = null;
   PreparedStatement pstmt = null;
   Statement stmt = null;
   ResultSet rs = null;
   try{
      // Register JDBC driver
      Class.forName("com.mysql.jdbc.Driver");

      // Open a connection
      System.out.println("Connecting to database...");
      conn = DriverManager.getConnection(DB_URL,USER,PASS);

      //Create a Statement object and build table
      stmt = conn.createStatement();
      createXMLTable(stmt);

      //Open a FileInputStream
      File f = new File("XML_Data.xml");
      long fileLength = f.length();
      FileInputStream fis = new FileInputStream(f);

      //Create PreparedStatement and stream data
      String SQL = "INSERT INTO XML_Data VALUES (?,?)";
      pstmt = conn.prepareStatement(SQL);
      pstmt.setInt(1,100);
      pstmt.setAsciiStream(2,fis,(int)fileLength);
      pstmt.execute();

      //Close input stream
      fis.close();

      // Do a query to get the row
      SQL = "SELECT Data FROM XML_Data WHERE id=100";
      rs = stmt.executeQuery (SQL);
      // Get the first row
      if (rs.next ()){
         //Retrieve data from input stream
         InputStream xmlInputStream = rs.getAsciiStream (1);
         int c;
         ByteArrayOutputStream bos = new ByteArrayOutputStream();
         while (( c = xmlInputStream.read ()) != -1)
            bos.write(c);
         //Print results
         System.out.println(bos.toString());
      }
      // Clean-up environment
      rs.close();
      stmt.close();
      pstmt.close();
      conn.close();
   }catch(SQLException se){
      //Handle errors for JDBC
      se.printStackTrace();
   }catch(Exception e){
      //Handle errors for Class.forName
      e.printStackTrace();
   }finally{
      //finally block used to close resources
      try{
         if(stmt!=null)
            stmt.close();
      }catch(SQLException se2){
      }// nothing we can do
      try{
         if(pstmt!=null)
            pstmt.close();
      }catch(SQLException se2){
      }// nothing we can do
      try{
         if(conn!=null)
            conn.close();
      }catch(SQLException se){
         se.printStackTrace();
      }//end finally try
   }//end try
   System.out.println("Goodbye!");
}//end main

public static void createXMLTable(Statement stmt) 
   throws SQLException{
   System.out.println("Creating XML_Data table..." );
   //Create SQL Statement
   String streamingDataSql = "CREATE TABLE XML_Data " +
                             "(id INTEGER, Data LONG)";
   //Drop table first if it exists.
   try{
      stmt.executeUpdate("DROP TABLE XML_Data");
   }catch(SQLException se){
   }// do nothing
   //Build table.
   stmt.executeUpdate(streamingDataSql);
}//end createXMLTable
}//end JDBCExample

如今,讓咱們用下面的命令編譯上面的代碼-

C:\>javac JDBCExample.java
C:\>

當你運行 JDBCExample 時,它將展現下面的結果-

C:\>java JDBCExample
Connecting to database...
Creating XML_Data table...
<?xml version="1.0"?>
<Employee>
<id>100</id>
<first>Zara</first>
<last>Ali</last>
<Salary>10000</Salary>
<Dob>18-08-1978</Dob>
<Employee>
Goodbye!
相關文章
相關標籤/搜索