jdbc知識點(連接mysql)


jdbc連接mysql

 

1.JDBC簡介

JDBC:

  指 Java 數據庫連接,是一種標准Java應用編程接口( JAVA API),用來連接 Java 編程語言和廣泛的數據庫。從根本上來說,JDBC 是一種規范,它提供了一套完整的接口,允許便攜式訪問到底層數據庫

 

常見的 JDBC 組件:

 JDBC 的 API 提供了以下接口和類:

  DriverManager :這個類管理一系列數據庫驅動程序。匹配連接使用通信子協議從 JAVA 應用程序中請求合適的數據庫驅動程序。識別 JDBC 下某個子協議的第一驅動程序將被用於建立數據庫連接。

  Driver : 這個接口處理與數據庫服務器的通信。你將很少直接與驅動程序互動。相反,你使用 DriverManager 中的對象,它管理此類型的對象。它也抽象與驅動程序對象工作相關的詳細信息。

  Connection : 此接口具有接觸數據庫的所有方法。該連接對象表示通信上下文,即,所有與數據庫的通信僅通過這個連接對象進行。

  Statement : 使用創建於這個接口的對象將 SQL 語句提交到數據庫。除了執行存儲過程以外,一些派生的接口也接受參數。

  ResultSet : 在你使用語句對象執行 SQL 查詢后,這些對象保存從數據獲得的數據。它作為一個迭代器,讓您可以通過它的數據來移動。

  SQLException : 這個類處理發生在數據庫應用程序的任何錯誤。

 

JDBC 4.0 軟件包:

  JDBC 4.0 主要包含 java.sql 包和 javax.sql 包,提供的主要類與數據源進行交互。

 

2.JDBC SQL語法

SQL語法:

  結構化查詢語言(SQL)是一種標准化的語言,可以讓你對數據庫進行curd操作,如創建項目,讀取內容,更新內容和刪除項目。SQL 支持你可能會使用到的任何數據庫,它可以讓你編寫獨立於底層數據庫的數據庫代碼

 

創建數據庫語法:create database 數據庫名;
如:create database hejh;
刪除數據庫語法:drop database 數據庫名;
如:drop database hejh;

注意:1.創建或刪除數據庫,必須有數據庫服務器的管理員權限;

   2.刪除數據庫會把存儲在該數據庫中的數據一並刪除。

 

創建表語法:
  create table 表名(
      字段名1 字段類型1,
     字段名2 字段類型2,
    ......
  );
建表示例:
  create table hejh(
    id int not null,
    age int not null,
    frist varchar(20),
    last varchar(20),
    primary key(id)
  );
刪除表語法:drop table 表名;
如:drop table hejh;

 

insert語法:insert into 表名 values(字段值1,字段值2,...); --(這種方式默認插入所有字段的值) 
如:insert into hejh values(1,22,'19990405','20190505');

 

select語法:select 字段1,字段2,... from 表名  where 查詢限制條件;
  如:select * from hejh where id=1;

注意:WHERE 子句可以使用 =,!=,<,>,<=,>=,BETWEEN 和 LIKE 這些比較操作符。

 

update語法:updata 表名 set 字段=字段新值 where 條件;
如:update hejh set age=33 where id=1;
注意:where子句可以使用=,!=,<,>,<=,>=,between和 like 這些比較操作符。

 

delete語法:delete from 表名 where 條件;
如:delete from hejh where id=1;
注意:where子句可以使用=,!=,<,>,<=,>=,between 和 like 這些比較操作符

 

 3.設置JDBC使用環境

 

 在開始使用 JDBC 之前,必須設置 JDBC 環境。(以mysql、windows系統為例)

  1.安裝jdk,配置環境變量;

  2.安裝mysql數據庫;

  3.安裝eclipse;

 

4.JDBC簡單示例

創建數據庫:hejh;

  create database hejh;

  

 

創建用戶表:user表

create table user( id int(5) not null, username varchar(20) not null, gender varchar(4), primary key(id) );

 

初始化數據:

 

 

創建JDBC應用程序

構建一個 JDBC 應用程序包括以下六個步驟:

  • 導入數據包:導入含有需要進行數據庫編程的 JDBC 類的包。大多數情況下,使用 import java.sql.就足夠了。

  • 注冊 JDBC 驅動器:需要你初始化一個驅動器,以便於你打開一個與數據庫的通信通道。

  • 打開連接:需要使用 DriverManager.getConnection() 方法創建一個 Connection 對象,它代表與數據庫的物理連接。

  • 執行查詢:需要使用類型聲明的對象建立並提交一個 SQL 語句到數據庫。

  • 提取結果數據:要求使用適當的 ResultSet.getXXX() 方法從結果集中檢索數據。

  • 清理環境:依靠 JVM 的垃圾收集來關閉所有需要明確關閉的數據庫資源。

 

查看數據庫hejh中user表的數據有3條:

 

 java源碼如下:

package com.hejh.day0506; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import org.junit.Test; public class JdbcTest1 { static final String driver = "com.mysql.jdbc.Driver"; static final String url = "jdbc:mysql://localhost/hejh"; static final String user = "root"; static final String password = "root"; //開啟junit局部測試 @Test public void run() { ResultSet rs=null; Statement st = null; Connection conn =null; try { //注冊驅動
 Class.forName(driver); //獲取連接
            conn = DriverManager.getConnection(url, user, password); //獲取sql執行對象
            st = conn.createStatement(); //編寫sql語句
            String sql = "select * from user"; //執行sql語句,返回一個結果集
            rs = st.executeQuery(sql); //處理結果集
            while(rs.next()) { int id = rs.getInt("id"); String name = rs.getString("username"); String gender = rs.getString("gender"); System.out.println("["+id+","+name+","+gender+"]"); } } catch (Exception e) { e.printStackTrace(); }finally {
       //關閉資源,后開啟的先關閉
try { if(rs!=null) { rs.close(); }else { rs=null; } } catch (SQLException e) { e.printStackTrace(); } if(st!=null) { try { st.close(); } catch (SQLException e) { e.printStackTrace(); } }else { st=null; } if(conn!=null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } }else { conn=null; } } } }

junit局部測試結果如下:

第一個jdbc案例完成。

 

4.JDBC 驅動類型

什么是 JDBC 驅動程序?

  JDBC 驅動實現了 JDBC API 中定義的接口,該接口用於與數據庫服務器進行交互。例如,使用 JDBC 驅動程序可以讓你打開數據庫連接,並通過發送 SQL 或數據庫命令,然后通過 Java 接收結果。java.sql 包中附帶的 JDK,包含了定義各種類與他們的行為和實際實現,這些類都在第三方驅動程序中完成。第三方供應商在他們的數據庫驅動程序中都實現了 java.sql.Driver 接口。

 

JDBC驅動程序類型:

  JDBC 驅動程序的實現,因為各種各樣的操作系統和 Java 運行在硬件平台的不同而不同。Sun 公司將實現類型分為四類:

    1.JDBC-ODBC橋驅動程序

    2.JDBC-Native API

    3.JDBC-Net純Java

    4.100%純Java

具體參見資料:https://www.w3cschool.cn/jdbc/j3xk1myd.html

  

該使用哪種驅動程序?

  如果你正在訪問一個數據庫,如 Oracle,Sybase 或 IBM,首選的驅動程序是類型4。

  如果你的 Java 應用程序同時訪問多個數據庫類型,類型3是首選的驅動程序。

  類型2驅動程序是在你的數據庫沒有提供類型3或類型4驅動程序時使用的。

  類型1驅動程序不被認為是部署級的驅動程序,它存在的目的通常僅用於開發和測試。

 

 5.JDBC連接數據庫

 

編寫建立一個 JDBC 連接的程序是相當簡單的,下面是簡單的四個步驟:

  • 導入 JDBC 包:在你的 Java 代碼中,用 import 語句添加你所需的類。

  • 注冊 JDBC 驅動程序:這一步會導致 JVM 加載所需的驅動程序到內存中執行,因此它可以實現你的 JDBC 請求。

  • 數據庫 URL 制定:這是用來創建格式正確的地址指向你想要連接的數據庫。

  • 創建連接對象:最后,代碼調用 DriverManager 對象的 getConnection() 方法來建立實際的數據庫連接。

 

1.導入jar包

  import 語句告訴 Java 編譯器在哪里可以找到你在代碼中引用的類,這些引用放置在你的源代碼起始位置。使用標准的 JDBC 包,它允許你選擇,插入,更新和刪除 SQL 表中的數據,添加以下引用到您的源代碼中。

import java.sql.*; import javax.sql.*;

 

2.注冊JDBC驅動程序  

  方法1 - Class.forName()

   注冊一個驅動程序中最常用的方法是使用 Java 的Class.forName() 方法來動態加載驅動程序的類文件到內存中,它會自動將其注冊。這種方法更優越一些,因為它允許你對驅動程序的注冊信息進行配置,便於移植。

//注冊驅動
Class.forName(“com.mysql.jdbc.Driver”);//會報異常

 

  方法2 - DriverManager.registerDriver() 

  你注冊一個驅動程序的第二種方法是使用靜態 staticDriverManager.registerDriver() 方法。如果你使用的是不兼容 JVM 的非 JDK,比如微軟提供的,你必須使用 registerDriver() 方法

try { Driver myDriver = new oracle.jdbc.driver.OracleDriver(); DriverManager.registerDriver( myDriver ); } catch(ClassNotFoundException ex) { System.out.println("Error: unable to load driver class!"); System.exit(1); }

 

 3.數據庫url制定

  當你加載了驅動程序之后,你可以通過 DriverManager.getConnection() 方法建立一個連接。

為方便參考,以下列出了三個加載 DriverManager.getConnection() 方法:

  • getConnection(String url)
  • getConnection(String url, Properties prop)
  • getConnection(String url, String user, String password)

  在這里,每個格式需要一個數據庫 URL ,數據庫 URL 是指向數據庫的地址。在建立一個數據連接的時候,大多數會在配置一個數據庫 URL 時遇到問題。下表列出了常用的 JDBC 驅動程序名和數據庫URL。

RDBMS JDBC 驅動程序名稱 URL 格式
MySQL com.mysql.jdbc.Driver jdbc:mysql://hostname/ databaseName
ORACLE oracle.jdbc.driver.OracleDriver jdbc:oracle:thin:@hostname:port Number:databaseName
DB2 COM.ibm.db2.jdbc.net.DB2Driver jdbc:db2:hostname:port Number/databaseName
Sybase com.sybase.jdbc.SybDriver jdbc:sybase:Tds:hostname: port Number/databaseName

 URL 格式所有加粗的部分都是靜態的,你需要將剩余部分按照你的數據庫實際情況進行設置

 

4.創建連接對象 

 調用適當的用戶名和密碼以及 getConnection() 方法來獲得一個 Connection 對象

static final String url = "jdbc:mysql://localhost/hejh";
static final String user = "root";
static final String password = "root";

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

 

使用數據庫 URL 和 Properties 對象:

  第三種 DriverManager.getConnection() 方法調用需要數據庫 URL 和 Properties 對象-

DriverManager.getConnection(String url, Properties info);

  Properties 對象保存了一組關鍵數值。它通過調用 getConnection() 方法,將驅動程序屬性傳遞給驅動程序。使用下面的代碼可以建立與上述示例相同的連接:

import java.util.*; String URL = "jdbc:mysql://localhost/hejh"; Properties info = new Properties( ); info.put( "user", "username" ); info.put( "password", "password" ); Connection conn = DriverManager.getConnection(URL, info);

 

5.關閉 JDBC 連接

  在 JDBC 程序的末尾,必須明確關閉所有連接到數據庫的連接,以結束每個數據庫會話。但是,如果忘了,Java 垃圾收集器也會關閉連接,它會完全清除過期的對象。依托垃圾收集器,特別是在數據庫編程,是非常差的編程習慣。你應該養成用 close()方法關閉連接對象的習慣。為了確保連接被關閉,你可以在代碼中的 'finally' 程序塊中執行。 無論異常是否發生,finally 程序是肯定會被執行的。要關閉上面打開的連接,應該調用 close()方法,如下所示:

finally { try { if(rs!=null) { rs.close(); }else { rs=null; } } catch (SQLException e) { e.printStackTrace(); } if(st!=null) { try { st.close(); } catch (SQLException e) { e.printStackTrace(); } }else { st=null; } if(conn!=null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } }else { conn=null; } }

 

6.JDBC Statement 對象

 

1.Statement 對象

  獲得了數據庫的連接,就可以和數據庫進行交互了。JDBC 的 Statement,CallableStatement 和 PreparedStatement 接口定義的方法和屬性,可以發送 SQL 命令或 PL/SQL 命令到數據庫,並從數據庫接收數據。在數據庫中,它們還定義了幫助 Java 和 SQL 數據類型之間轉換數據差異的方法。下表提供了每個接口的用途概要,根據實際目的決定使用哪個接口。

接口 推薦使用
Statement 可以正常訪問數據庫,適用於運行靜態 SQL 語句。 Statement 接口不接受參數。
PreparedStatement 計划多次使用 SQL 語句, PreparedStatement 接口運行時接受輸入的參數。
CallableStatement 適用於當你要訪問數據庫存儲過程的時候, CallableStatement 接口運行時也接受輸入的參數。

 

創建 Statement 對象:

使用 Statement 對象執行 SQL 語句之前,需要用 Connection 對象創建一個 Statement()對象,如下面的示例所示:

Statement stmt = null; try { stmt = conn.createStatement( ); . . . } catch (SQLException e) { . . . } finally { . . . }

 

當創建了一個 Statement 對象之后,可以用它的三個執行方法的任一方法來執行 SQL 語句:

  • boolean execute(String SQL) : 如果 ResultSet 對象可以被檢索,則返回的布爾值為 true ,否則返回 false 。當你需要使用真正的動態 SQL 時,可以使用這個方法來執行 SQL DDL 語句。

  • int executeUpdate(String SQL) : 返回執行 SQL 語句影響的行的數目。使用該方法來執行 SQL 語句,是希望得到一些受影響的行的數目,例如,INSERT,UPDATE 或 DELETE 語句。

  • ResultSet executeQuery(String SQL) : 返回一個 ResultSet 對象。當你希望得到一個結果集時使用該方法,就像你使用一個 SELECT 語句。

 

關閉 Statement 對象:

  正如關閉一個 Connection 對象來節約數據庫資源,出於同樣的原因你也應該關閉 Statement 對象。簡單的調用 close() 方法就可以完成這項工作。如果關閉了 Connection 對象,那么它也會關閉 Statement 對象。然而,你應該始終明確關閉 Statement 對象,以確保真正的清除。

Statement stmt = null; try { stmt = conn.createStatement( ); . . . } catch (SQLException e) { . . . } finally { stmt.close();//會報異常 }

 

PreparedStatement 對象:

  PreparedStatement 接口擴展了 Statement 接口,它讓你用一個常用的 Statement 對象增加幾個高級功能。這個 statement 對象可以提供靈活多變的動態參數。創建 PreparedStatement 對象:

PreparedStatement pstmt = null; try { String SQL = "update user set age = ? where id = ?"; pstmt = conn.prepareStatement(SQL);
  psmt.setInt(1,22);
  psmt.setInt(2,1); . . . }
catch (SQLException e) { . . . } finally { . . . }

  JDBC 中所有的參數都被用 ? 符號表示,這是已知的參數標記。在執行 SQL 語句之前,你必須賦予每一個參數確切的數值。setXXX() 方法將值綁定到參數,其中 XXX 表示你希望綁定到輸入參數的 Java 數據類型。如果你忘了賦予值,你將收到一個 SQLException。每個參數標記映射它的序號位置。第一標記表示位置 1 ,下一個位置為 2 等等。這種方法不同於 Java 數組索引是從 0 開始的。所有的 Statement對象 的方法都與數據庫交互,(a) execute(),(b) executeQuery(),及 (c) executeUpdate() 也能被 PreparedStatement 對象引用。然而,這些方法被 SQL 語句修改后是可以輸入參數的。

 

關閉 PreparedStatement 對象

  關閉 PreparedStatement 對象,簡單的調用 close() 方法可以完成這項工作。如果你關閉了 Connection 對象,那么它也會關閉 PreparedStatement 對象。然而,你應該始終明確關閉 PreparedStatement 對象,以確保真正的清除。

PreparedStatement pstmt = null; try { String SQL = "Update Employees SET age = ? WHERE id = ?"; pstmt = conn.prepareStatement(SQL); . . . } catch (SQLException e) { . . . } finally { pstmt.close();//會報異常
}

 

CallableStatement 對象:

  正如一個 Connection 對象可以創建 Statement 對象和 PreparedStatement 對象,它也可以創建被用來執行調用數據庫存儲過程的 CallableStatement 對象。

 在 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 對象可以使用所有的三個參數。這里是每個參數的定義:

參數 描述
IN 在 SQL 語句創建的時候該參數是未知的。你可以用 setXXX() 方法將值綁定到IN參數中。
OUT 該參數由 SQL 語句的返回值提供。你可以用 getXXX() 方法獲取 OUT 參數的值。
INOUT 該參數同時提供輸入輸出的值。你可以用 setXXX() 方法將值綁定參數,並且用 getXXX() 方法獲取值。

 下面的代碼片段展示了基於存儲過程如何使用 Connection.prepareCall() 方法來實例化 CallableStatement 對象。

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

 

 7.結果集

 結果集:

  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的類型:

  可能的 RSType 如下所示。如果你不指定 ResultSet 類型,將自動獲得的值是 TYPE_FORWARD_ONLY。

類型 描述
ResultSet.TYPE_FORWARD_ONLY 光標只能在結果集中向前移動。
ResultSet.TYPE_SCROLL_INSENSITIVE 光標可以向前和向后移動。當結果集創建后,其他人對數據庫的操作不會影響結果集的數據。
ResultSet.TYPE_SCROLL_SENSITIVE. 光標可以向前和向后移動。當結果集創建后,其他人對數據庫的操作會影響結果集的數據。

 

ResultSet的並發性:

  RSConcurrency 的值如下所示,如果你不指定並發類型,將自動獲得的值是 CONCUR_READ_ONLY。

並發性 描述
ResultSet.CONCUR_READ_ONLY 創建一個只讀結果集,這是默認的值。
ResultSet.CONCUR_UPDATABLE 創建一個可修改的結果集。

示例可以如下所示,初始化一個 Statement 對象,來創建一個只能前進而且只讀的 ResultSet 對象:

try { Statement stmt = conn.createStatement( ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); } catch(Exception ex) { .... } finally { .... }

 

導航結果集:

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

S.N. 方法 & 描述
1 public void beforeFirst() throws SQLException

將光標移動到第一行之前。

2 public void afterLast() throws SQLException

將光標移動到最后一行之后。

3 public boolean first() throws SQLException

將光標移動到第一行。

4 public void last() throws SQLException

將光標移動到最后一行。

5 public boolean absolute(int row) throws SQLException

將光標移動到指定的第 row 行。

6 public boolean relative(int row) throws SQLException

將光標移動到當前指向的位置往前或往后第 row 行的位置。

7 public boolean previous() throws SQLException

將光標移動到上一行,如果超過結果集的范圍則返回 false。

8 public boolean next() throws SQLException

將光標移動到下一行,如果是結果集的最后一行則返回 false。

9 public int getRow() throws SQLException

返回當前光標指向的行數的值。

10 public void moveToInsertRow() throws SQLException

將光標移動到結果集中指定的行,可以在數據庫中插入新的一行。當前光標位置將被記住。

11 public void moveToCurrentRow() throws SQLException

如果光標處於插入行,則將光標返回到當前行,其他情況下,這個方法不執行任何操作。

 

查看結果集:

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()

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

 

8.JDBC數據類型

 

  JDBC 驅動程序在將 Java 數據類型數據發送到數據庫之前,會將其轉換為相應的 JDBC 類型數據,對於大多數數據類型都采用了默認的映射關系。例如,一個 Java int 數據類型轉換為 SQL INTEGER。通過默認的映射關系來提供驅動程序之間的一致性。當你調用 PreparedStatement 中的 setXXX()方法或 CallableStatement 對象或 ResultSet.updateXXX()方法時, Java 數據類型會轉換為默認的 JDBC 數據類型,如下表概述。

SQL JDBC/Java setXXX updateXXX
VARCHAR java.lang.String setString updateString
CHAR java.lang.String setString updateString
LONGVARCHAR java.lang.String setString updateString
BIT boolean setBoolean updateBoolean
NUMERIC java.math.BigDecimal setBigDecimal updateBigDecimal
TINYINT byte setByte updateByte
SMALLINT short setShort updateShort
INTEGER int setInt updateInt
BIGINT long setLong updateLong
REAL float setFloat updateFloat
FLOAT float setFloat updateFloat
DOUBLE double setDouble updateDouble
VARBINARY byte[ ] setBytes updateBytes
BINARY byte[ ] setBytes updateBytes
DATE java.sql.Date setDate updateDate
TIME java.sql.Time setTime updateTime
TIMESTAMP java.sql.Timestamp setTimestamp updateTimestamp
CLOB java.sql.Clob setClob updateClob
BLOB java.sql.Blob setBlob updateBlob
ARRAY java.sql.Array setARRAY updateARRAY
REF java.sql.Ref SetRef updateRef
STRUCT java.sql.Struct SetStruct updateStruct


  JDBC 3.0 增強了對 BLOB,CLOB,ARRAY 和 REF 數據類型的支持。 ResultSet 對象現在有 UPDATEBLOB(),updateCLOB(), updateArray(),和 updateRef()方法,通過這些方法你可以直接操作服務器上的相應數據。

你能用 setXXX()方法和 updateXXX()方法將 Java 類型轉換為特定的 JDBC 數據類型。你能用 setObject()方法和 updateObject()方法將絕大部分的 Java 類型映射到 JDBC 數據類型。

  ResultSet 對象為任一數據類型提供相應的 getXXX()方法,該方法可以獲取任一數據類型的列值。上述任一方法的使用需要列名或它的順序位置。

SQL JDBC/Java setXXX getXXX
VARCHAR java.lang.String setString getString
CHAR java.lang.String setString getString
LONGVARCHAR java.lang.String setString getString
BIT boolean setBoolean getBoolean
NUMERIC java.math.BigDecimal setBigDecimal getBigDecimal
TINYINT byte setByte getByte
SMALLINT short setShort getShort
INTEGER int setInt getInt
BIGINT long setLong getLong
REAL float setFloat getFloat
FLOAT float setFloat getFloat
DOUBLE double setDouble getDouble
VARBINARY byte[ ] setBytes getBytes
BINARY byte[ ] setBytes getBytes
DATE java.sql.Date setDate getDate
TIME java.sql.Time setTime getTime
TIMESTAMP java.sql.Timestamp setTimestamp getTimestamp
CLOB java.sql.Clob setClob getClob
BLOB java.sql.Blob setBlob getBlob
ARRAY java.sql.Array setARRAY getARRAY
REF java.sql.Ref SetRef getRef
STRUCT java.sql.Struct SetStruct getStruct

 

日期和時間數據類型:

  java.sql.Date 類映射 SQL DATE 類型,java.sql.Time 類和 java.sql.Timestamp 類也分別映射 SQL TIME 數據類型和 SQL TIMESTAMP 數據類型。以下示例顯示了日期和時間類如何轉換成標准的 Java 日期和時間值,並匹配成 SQL 數據類型所要求的格式。

package com.hejh.day0507; import java.util.Date; public class TimeTest { public static void main(String[] args) { //java util 打印當前具體時間
        Date utilDate = new Date(); long utilTime = utilDate.getTime(); System.out.println("java util date:"+utilDate.toString());//java util date:Tue May 07 17:14:53 CST 2019 //sql 打印當前時間(某年-某月-某日)
        java.sql.Date sqlDate  = new java.sql.Date(utilTime); System.out.println("java sql date:"+sqlDate.toString());//java sql date:2019-05-07 //sql 打印當前時間(時:分:秒)
        java.sql.Time sqlTime  = new java.sql.Time(utilTime); System.out.println("java sql time:"+sqlTime.toString());//java sql time:17:34:33 //sql 打印當前具體時間(某年-某月-某日 時:分:秒)
        java.sql.Timestamp sqlTimeStamp  = new java.sql.Timestamp(utilTime); System.out.println("java sql Timestamp:"+sqlTimeStamp.toString());//java sql Timestamp:2019-05-07 17:36:44.176 
 } }

 

處理 NULL 值:

SQL 使用 NULL 值和 Java 使用 null 是不同的概念。那么,你可以使用三種策略來處理 Java 中的 SQL NULL 值:

  • 避免使用返回原始數據類型的 getXXX()方法。
  • 使用包裝類的基本數據類型,並使用 ResultSet 對象的 wasNull()方法來測試收到 getXXX()方法返回的值是否為 null,如果是 null,該包裝類變量則被設置為 null。
  • 使用原始數據類型和 ResultSet 對象的 wasNull()方法來測試通過 getXXX()方法返回的值,如果是 null,則原始變量應設置為可接受的值來代表 NULL。

下面是一個處理 NULL 值的示例:

Statement stmt = conn.createStatement( ); String sql = "SELECT id, first, last, age FROM Employees"; ResultSet rs = stmt.executeQuery(sql); int id = rs.getInt(1); if( rs.wasNull( ) ) { id = 0; }

 

 9.JDBC事務

事務: 

  如果 JDBC 連接是處於自動提交模式下,該模式為默認模式,那么每句 SQL 語句都是在其完成時提交到數據庫。對簡單的應用程序來說這種模式相當好,但有三個原因你可能想關閉自動提交模式,並管理你自己的事務:

  • 為了提高性能
  • 為了保持業務流程的完整性
  • 使用分布式事務

你可以通過事務在任意時間來控制以及更改應用到數據庫。它把單個 SQL 語句或一組 SQL 語句作為一個邏輯單元,如果其中任一語句失敗,則整個事務失敗。

  若要啟用手動事務模式來代替 JDBC 驅動程序默認使用的自動提交模式的話,使用 Connection 對象的的 setAutoCommit()方法。如果傳遞一個布爾值 false 到 setAutoCommit()方法,你就關閉自動提交模式。你也可以傳遞一個布爾值 true 將其再次打開。例如,如果有一個名為 conn 的 Connection 對象,以下的代碼將關閉自動提交模式:

conn.setAutoCommit(false);//關閉自動提交模式

 

 提交和回滾:

   當完成修改,並且要提交修改,可以在 connection 對象里調用 commit()方法,如下所示:

conn.commit( );

  

在默認情況下,事務自動提交,源碼和數據庫數據如下:

package com.hejh.day0508; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import org.junit.Test; public class AffairTest { static final String driver = "com.mysql.jdbc.Driver"; static String url = "jdbc:mysql://localhost/hejh"; static final String username = "root"; static final String password = "root"; @Test public void run() { Connection conn = null; PreparedStatement ps = null; try { Class.forName(driver); conn = DriverManager.getConnection(url, username, password); String sql = "update user set username = ?  where id = ? "; ps = conn.prepareStatement(sql); ps.setString(1,"hejh11"); ps.setInt(2, 1); int i = ps.executeUpdate(); System.out.println("影響了:"+i+"行");        //影響了:1行
        } catch (Exception e) { e.printStackTrace(); }finally { try { if(ps!=null) { ps.close(); }else { ps=null; } } catch (Exception e) { e.printStackTrace(); } try { if(conn!=null) { conn.close(); }else { conn=null; } } catch (SQLException e) { e.printStackTrace(); } }//finally
 } }

 

設置為手動提交,運行下面的源碼(替換try-catch部分代碼),數據庫數據刷新結果如下:

try { Class.forName(driver); conn = DriverManager.getConnection(url, username, password); String sql = "update user set username = ?  where id = ? "; //在執行sql之前,設置事務為手動提交
            conn.setAutoCommit(false);//手動提交事務,數據不會發生變化
            ps = conn.prepareStatement(sql); ps.setString(1,"hejh111"); ps.setInt(2, 1); int i = ps.executeUpdate(); System.out.println("影響了:"+i+"行");        //影響了:1行
        } catch (Exception e) { e.printStackTrace(); }

 

 設置為手動提交,並且在sql執行后,手動提交一下事務,運行下面的源碼(替換try-catch部分代碼),數據庫數據刷新結果如下:

try { Class.forName(driver); conn = DriverManager.getConnection(url, username, password); String sql = "update user set username = ?  where id = ? "; //在執行sql之前,設置事務為手動提交
            conn.setAutoCommit(false);//手動提交事務,數據不會發生變化
            ps = conn.prepareStatement(sql); ps.setString(1,"hejh111"); ps.setInt(2, 1); int i = ps.executeUpdate(); //sql語句執行后,手動提交事務,使sql生效
 conn.commit(); System.out.println("影響了:"+i+"行");        //影響了:1行
        } catch (Exception e) { e.printStackTrace(); }

 

 另外,用名為 conn 的連接回滾數據到數據庫,

conn.rollback( );//可以放在catch塊中

 

還原點:

  新的 JDBC 3.0 還原點接口提供了額外的事務控制。大部分現代的數據庫管理系統的環境都支持設定還原點,例如 Oracle 的 PL/SQL。當你在事務中設置一個還原點來定義一個邏輯回滾點。如果在一個還原點之后發生錯誤,那么可以使用 rollback 方法來撤消該還原點之后所做的修改。

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

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

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

有一個 rollback (String savepointName) 方法,該方法可以回滾到指定的還原點。下面的例子說明了如何使用 Savepoint 對象:

package com.hejh.day0508;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Savepoint;

import org.junit.Test;

public class SavePointTest {
	
	@Test
	public void save() throws SQLException {
		Connection conn = null;
		 PreparedStatement ps =null;
		 Savepoint beforeInsert = null;
		try {
			Class.forName("com.mysql.jdbc.Driver");
			//prepareStatement插入的中文參數有可能會出現問號,可以在這里指定一下字符編碼為utf-8
			conn  = DriverManager.getConnection("jdbc:mysql://localhost/hejh?useUnicode=true&characterEncoding=UTF-8",
                                                             "root", "root"); //設置一個還原點 beforeInsert = conn.setSavepoint(); String sql = "insert into user values(?,?,?)"; ps = conn.prepareStatement(sql); ps.setInt(1,4); ps.setString(2, "hejh222"); ps.setString(3, "男"); int i = ps.executeUpdate(); System.out.println("插入了:"+i+"行數據"); } catch (Exception e) { //回滾到還原點BeforeInsert處 conn.rollback(beforeInsert); e.printStackTrace(); }finally { try { if(ps!=null) { ps.close(); }else { ps = null; } } catch (SQLException e) { e.printStackTrace(); } try { if(beforeInsert!=null) { conn.releaseSavepoint(beforeInsert); }else { beforeInsert=null; } } catch (SQLException e) { e.printStackTrace(); } try { if(conn!=null) { conn.close(); }else { conn=null; } } catch (SQLException e) { e.printStackTrace(); } } } }

  

 10.JDBC異常

 異常:

  異常處理可以允許你處理一個異常情況,例如可控方式的程序定義錯誤。當異常情況發生時,將拋出一個異常。拋出這個詞意味着當前執行的程序停止,控制器被重定向到最近的適用的 catch 子句。如果沒有適用的 catch 子句存在,那么程序執行被終止。JDBC 的異常處理是非常類似於 Java 的異常處理,但對於 JDBC,最常見的異常是 java.sql.SQLException

 

SQLException:

  SQLException 異常在驅動程序和數據庫中都可能出現。當出現這個異常時,SQLException 類型的對象將被傳遞到 catch 子句。傳遞的 SQLException 對象具有以下的方法,以下的方法可用於檢索該異常的額外信息:

方法 描述
getErrorCode( ) 獲取與異常關聯的錯誤號。
getMessage( ) 獲取 JDBC 驅動程序的錯誤信息,該錯誤是由驅動程序處理的,或者在數據庫錯誤中獲取 Oracl 錯誤號和錯誤信息。
getSQLState( ) 獲取 XOPEN SQLstate 字符串。對於 JDBC 驅動程序錯誤,使用該方法不能返回有用的信息。對於數據庫錯誤,返回第五位的 XOPEN SQLstate 代碼。該方法可以返回 null。
getNextException( ) 獲取異常鏈的下一個 Exception 對象。
printStackTrace( ) 打印當前異常或者拋出,其回溯到標准的流錯誤。
printStackTrace(PrintStream s) 打印該拋出,其回溯到你指定的打印流。
printStackTrace(PrintWriter w) 打印該拋出,其回溯到你指定的打印寫入。

 

通過利用可從 Exception 對象提供的信息,你可以捕獲異常並繼續運行程序。這是一個 try 塊的一般格式:

try { // 可能出現異常的代碼
} catch(Exception ex) { //異常的捕捉和處理
} finally {// 必須執行的操作,想數據庫的資源關閉,
}
package com.hejh.day0508; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Savepoint; import org.junit.Test; public class ExceptionTest { @Test public void save() throws SQLException { Connection conn = null; PreparedStatement ps =null; Savepoint beforeInsert = null; try { Class.forName("com.mysql.jdbc.Driver"); //1.數據庫用戶名和密碼不符(root,hejh),實際用戶名密碼為(root,root)
            conn  = DriverManager.getConnection("jdbc:mysql://localhost/hejh?useUnicode=true&characterEncoding=UTF-8", "root", "hejh"); String sql = "insert into user values(?,?,?)"; ps = conn.prepareStatement(sql); ps.setInt(1,4); ps.setString(2, "hejh200"); ps.setString(3, "男"); int i = ps.executeUpdate(); System.out.println("插入了:"+i+"行數據"); } catch (Exception e) { //2.在這里捕獲異常,並將異常信息打印到控制台
 e.printStackTrace(); }finally { try { if(ps!=null) { ps.close(); }else { ps = null; } } catch (SQLException e) { e.printStackTrace(); } try { if(beforeInsert!=null) { conn.releaseSavepoint(beforeInsert); }else { beforeInsert=null; } } catch (SQLException e) { e.printStackTrace(); } try { if(conn!=null) { conn.close(); }else { conn=null; } } catch (SQLException e) { e.printStackTrace(); } } } }

出現以下異常:

java.sql.SQLException: Access denied for user 'root'@'localhost' (using password: YES)
......

 

 11.JDBC批處理

 批處理:

  批處理是指你將關聯的 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() 方法提交所有的更改。

批量執行3條insert語句,示例如下:

package com.hejh.day0508; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; import org.junit.Test; import org.omg.Messaging.SyncScopeHelper; //批處理
public class Batching { @Test public void test() { Connection conn = null; Statement st = null; try { //注冊驅動
            Class.forName("com.mysql.jdbc.Driver"); //獲取鏈接
            conn = DriverManager.getConnection("jdbc:mysql://localhost/hejh?useUnicode=true&characterEncoding=UTF-8", "root", "root"); //設置為:手動提交事務
            conn.setAutoCommit(false); //編寫3個insert sql語句
            String sql1 = "insert into user values(4,'sss','女')"; String sql2 = "insert into user values(5,'www','男')"; String sql3 = "insert into user values(6,'yyy','女')"; //獲取statement對象
            st = conn.createStatement(); //添加sql語句到批處理
 st.addBatch(sql1); st.addBatch(sql2); st.addBatch(sql3); //執行批處理,返回一個整數數組,數組中的每個元素代表了各自的更新語句的更新數目
            int[] arr = st.executeBatch(); //事務提交,使sql語句生效
 conn.commit(); //處理數組
            System.out.print("影響行數為:"); for(int i=0;i<arr.length;i++) { System.out.print(arr[i]+"  ");//影響行數為:1 1 1 
 } } catch (Exception e) { e.printStackTrace(); }finally { try { if(st!=null) { st.close(); }else { st = null; } } catch (SQLException e) { e.printStackTrace(); } try { if(conn!=null) { conn.close(); }else { conn = null; } } catch (SQLException e) { e.printStackTrace(); } } } }

 

批處理和 PrepareStatement 對象:

使用 prepareStatement 對象來使用批處理需要的典型步驟如下所示:

  • 使用占位符創建 SQL 語句。
  • 使用任一 prepareStatement() 方法創建 prepareStatement 對象。
  • 使用 setAutoCommit() 方法將自動提交設為 false。
  • 被創建的 Statement 對象可以使用 addBatch() 方法來添加你想要的所有 SQL 語句。
  • 被創建的 Statement 對象可以用 executeBatch() 將所有的 SQL 語句執行。
  • 最后,使用 commit() 方法提交所有的更改。

 示例如下:

package com.hejh.day0508; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import org.junit.Test; public class PrepareStatementBatching { @Test public void test() { Connection conn = null; PreparedStatement ps = null; try { //注冊驅動
            Class.forName("com.mysql.jdbc.Driver"); //獲取鏈接
            conn = DriverManager.getConnection("jdbc:mysql://localhost/hejh?useUnicode=true&characterEncoding=UTF-8", "root", "root"); //設置為:手動提交事務
            conn.setAutoCommit(false); //編寫sql語句
            String sql = "update user set username=? where id=?"; //獲取statement對象
            ps = conn.prepareStatement(sql); //添加第一個sql語句到批處理
            ps.setString(1, "s"); ps.setInt(2, 4); ps.addBatch(); //添加第二個sql語句到批處理
            ps.setString(1, "w"); ps.setInt(2, 5); ps.addBatch(); //添加第三個sql語句到批處理
            ps.setString(1, "y"); ps.setInt(2, 6); ps.addBatch(); //執行批處理,返回一個整數數組,數組中的每個元素代表了各自的更新語句的更新數目
            int []arr  = ps.executeBatch(); //提交事務,使sql語句生效
 conn.commit(); //處理數組 
           System.out.print("分別影響了:"); for(int i=0;i<arr.length;i++) { System.out.print(arr[i]+"  "); //分別影響了:1行   1行   1行  } } catch (Exception e) { e.printStackTrace(); }finally { try { if(ps!=null) { ps.close(); }else { ps = null; } } catch (SQLException e) { e.printStackTrace(); } try { if(conn!=null) { conn.close(); }else { conn = null; } } catch (SQLException e) { e.printStackTrace(); } } } }

 

12.JDBC流數據

流數據:

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

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

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

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

 

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

<?xml version="1.0"?>
<hejh>
    <id>1</id>
    <username>hjh</username>
    <gender>男</gender>
</hejh>

將該 xml_data.xml文件和要運行的示例保存在相同的目錄的。這個示例將創建一個數據庫表 xml_data ,然后 xml_data.xml 將被上傳到該表中。

將下面的示例拷貝並粘帖到 JDBCStreamingDate.java 中,編譯並運行它,如下所示:

package com.hejh.day0509; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class JDBCStreamingDate { public static void main(String[] args)throws SQLException, IOException { Connection conn = null; Statement st = null; PreparedStatement pps = null; ResultSet rs = null; try { //注冊驅動
            Class.forName("com.mysql.jdbc.Driver"); //獲取連接
            conn = DriverManager.getConnection("jdbc:mysql://localhost/hejh?useUnicode=true&characterEncoding=UTF-8", "root", "root"); //獲取 Statement 對象,來創建一張xml_data表
            st = conn.createStatement(); createXMLTable(st); //將xml_data.xml文件讀取進來
            File file = new File("src/xml_data.xml"); long fileLength  = file.length(); FileInputStream fis = new FileInputStream(file); //獲取 對象,給表插入數據,並執行sql
            String sql = "insert into xml_data values(?,?)"; pps = conn.prepareStatement(sql); pps.setInt(1, 100); pps.setAsciiStream(2, fis,(int)fileLength ); pps.execute(); //關閉輸入流
 fis.close(); String selectSql = "select data from xml_data where id =100"; rs = st.executeQuery(selectSql); InputStream is = null; ByteArrayOutputStream bos = null; if(rs.next()) { is = rs.getAsciiStream(1); int c ; //獲取輸出流,將帶數據的hejh.xml文件輸出
                bos = new ByteArrayOutputStream(); while((c=is.read())!=-1) { bos.write(c); } } System.out.println(bos.toString()); } catch (ClassNotFoundException e) { e.printStackTrace(); }finally {//關閉資源
            if(rs!=null) { rs.close(); }else { rs = null; } if(pps!=null) { pps.close(); }else { pps = null; } if(st!=null) { st.close(); }else { st = null; } if(conn!=null) { conn.close(); }else { conn = null; } } } //創建一張表,表名xml_data
    public static void createXMLTable(Statement st) throws SQLException { //sql語句,創建一張表xml_data
 String createTable = "create table xml_data(id int,data long)"; //刪除表xml_data
        String dropTable  = "drop table xml_data"; //在建表前,應該先刪除表,如果存在相同的表名的話
        try { st.execute(dropTable); } catch (SQLException e) { e.printStackTrace(); } //創建表
 st.executeUpdate(createTable); } }

console輸出為:

<?xml version="1.0" encoding="UTF-8"?>
<hejh>
    <id>1</id>
    <username>hjh</username>
    <gender>男</gender>
</hejh>

數據庫表現為:

 

本博文參考w3cschool網JDBC指南一文,附上網址:https://www.w3cschool.cn/jdbc/bgqu1my6.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM