一文快速回顧 Java 運算元據庫的方式-JDBC

god23bin 發表於 2023-03-18
Java JDBC

前言

資料庫的重要性不言而喻,不管是什麼系統,什麼應用軟體,也不管它們是 Windows 上的應用程式,還是 Web 應用程式,儲存(持久化)和查詢(檢索)資料都是核心的功能。

大家學習資料庫時,比如 MySQL 這個資料庫管理系統,都是在 CLI(Command Line Interface)上運算元據庫的,現在,我們看看,在 Java Web 中,我們如何使用 Java 去運算元據庫。

JDBC

JDBC(Java Data Base Connectivity)是 Java 運算元據庫的一種規範,也是一種 API(與資料庫系統進行通訊的標準的 API),更是一門技術。

JDBC 是由一組用 Java 編寫的類和介面組成,對資料庫的操作提供了基本的方法。但是,對於資料庫細節的操作,那就是由資料庫的廠商實現的。使用 JDBC 運算元據庫,需要資料庫廠商提供的資料庫驅動程式的支援。

那什麼是資料庫驅動程式呢?這個驅動(driver)可以理解成一種可以讓資料庫和 Java 彼此進行互動的程式。

簡單來講,JDBC 提供了一種 API 的規範,告訴各大資料庫廠商按這種規範來實現這些 API 具體的實現程式碼。可以從兩個角色的角度來說這個 JDBC。從我們們開發人員的角度來說,JDBC 為我們開發人員提供了統一的運算元據庫的 API,不用管這些 API 的具體實現,專注於 API 的呼叫;從資料庫廠商的角度來說,JDBC 為他們提供了一套標準的模型介面,都按這個介面去做自己的實現。

如何使用 JDBC?

JDBC 的使用主要有如下幾個步驟:

  1. 註冊資料庫驅動程式(database driver program)到 JDBC 的驅動管理器中。

在連線資料庫之前,需要將資料庫廠商提供的資料庫驅動類註冊到 JDBC 的驅動管理器中,一般是把驅動類載入到 JVM 實現的。

Class.forName("com.mysql.jdbc.Driver");
  1. 構建資料庫連線的 URL。

要與資料庫建立連線,那麼就需要構建資料庫連線的 URL,這個 URL 由資料庫廠商指定,一般符合一種基本格式,即 JDBC協議+IP地址或域名+埠+資料庫名稱。MySQL 的 URL 是 jdbc:mysql://localhost:3306/dbname

  1. 獲取連線物件(Connection 物件)。
String url = "jdbc:mysql://localhost:3306/dbname";
String username = "root";
String password = "123456";
// Connection 物件的獲取需要藉助 DriverManager 物件
Connection conn = DriverManager.getConnection(url, username, password);
  1. 進行資料庫操作。

編寫 SQL,然後獲取 PreparedStatement 物件,對 SQL 語句進行執行。SQL 語句的引數是可以使用佔位符 “?” 代替,再透過 PreparedStatement 物件對 SQL 語句中的佔位符進行賦值。

Statment 這個單詞的意思在這裡指的就是 SQL 語句。
// 編寫SQL
String sql = "INSERT INTO tb_game(name, price, platform) values(?, ?, ?)";
// 獲取 PreparedStatement 物件
PreparedStatement ps = conn.preparedStatement(sql);
// 給佔位符賦值
ps.setString(1, "NBA2K");
ps.setDouble(2, 198.0);
ps.setString(3, "Windows");
// 執行 SQL,將這條資料寫入資料庫,返回影響的行數
int row = ps.executeUpdate();
使用 PreparedStatement 物件對 SQL 語句的佔位符引數賦值,其引數的下標是從 1 開始的。
  1. 關閉連線
conn.close();

CRUD

新增操作

新增操作,就是上面的插入操作,請看上面。

查詢操作

ResultSet

使用 JDBC 查詢資料,與插入資料的操作流程基本一樣,但是執行查詢操作後需要透過一個物件來接收查詢的結果,這個物件就是 ResultSet (結果集)。

ResultSet 是 JDBC API 中封裝的物件,從資料表中查到的所有記錄都會放在這個集合中。ResultSet 中維護著一個 cursor(遊標)來指向當前的資料行(資料記錄),初始化的時候,這個遊標指向第一行的前一行,可以透過 next() 方法來移動遊標,讓遊標指向下一行。

呼叫這個 next() 它返回的是一個布林值,為 true 說明 ResultSet 中還有下一行的資料,為 false 說明沒有,所以可以結合 while 迴圈使用這個方法來遍歷整個 ResultSet。

// 由於一開始的遊標在第一行的前一行,所以執行 next() 後,遊標就指向第一行的資料了
while (resultSet.next()) {
    // 處理結果集中每一行的資料
}

獲取到 ResultSet 物件後,移動了游標指定了資料行,然後透過 ResultSet 物件提供的一系列 getXxxx() 方法來獲取當前行的資料,比如 resultSet.getInt("price") 獲取當前行中欄位名為 price 的資料。

預設的 ResultSet 是不可更新的,同時它的遊標只能一步一步 next 下去,只能走一遍,不能回到上一行的。說了預設,那說明是可以設定的,透過如下程式碼進行設定:

Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
ResultSet rs = stmt.executeQuery("SELECT a, b FROM TABLE2");
// rs 是可以滾動的,也就是遊標走到最後又會回到開頭繼續走,並且它的內容是可以被改變的

查詢

找到價格大於50塊錢的所有遊戲:

String sql = "SELECT id, name, price FROM tb_game WHERE price > ?";
PreparedStatement ps = conn.preparedStatement(sql);
ps.setDouble(1, 50);
// 執行查詢
ResultSet rs = ps.executeQuery(sql);
List<Game> gameList = new ArrayList<>();
// 遍歷結果集
while (rs.next()) {
    Game game = new Game();
    // 獲取當前行中欄位名為 id 的資料,並賦值到 game 物件中
    game.setId(rs.getInt("id"));
    game.setName(rs.getString("name"));
    game.setPrice(rs.getDouble("price"));
    gameList.add(game);
}
System.out.println(gameList);

修改(更新)操作

修改(更新)資料的操作,也是和插入資料的操作是類似的。

更新 ID 為 3 的資料記錄,修改其價格為 298 塊錢。

String sql = "UPDATE tb_game SET price = ? WHERE id = ?";
PreparedStatement ps = conn.preparedStatement(sql);
ps.setDouble(1, 298);
ps.setInt(2, 3);
int row = ps.executeUpdate();

刪除操作

同理。

String sql = "DELETE FROM tb_game WHERE id = ?";
PreparedStatement ps = conn.preparedStatement(sql);
ps.setInt(1, 1);
int row = ps.executeUpdate();

分頁查詢

在 Java Web 中資料量非常大的情況下,是不利於將所有資料都展示到一個頁面中的,檢視不方便,又佔用系統資源。此時就需要對資料進行分頁查詢,同時,以後的工作中,可以說大部分的業務場景都會涉及到分頁查詢。

在 MySQL 中,分頁可以透過其自身的 LIMIT 關鍵字來實現:

SELECT *
FROM tb_game
WHERE price > 50
ORDER BY price DESC
LIMIT 0, 10; // 從表中下標0開始(第一行的下標為0),限制返回10條記錄

目前分頁涉及到這樣的兩個引數:當前頁碼頁面大小

涉及的 SQL 語句:SELECT * FROM tb_game WHERE price > 50 ORDER BY price DESC LIMIT 當前頁碼, 頁面大小

// 分頁引數
int currentPage = 1, pageSize = 10;
// 分頁 SQL
String sql = "SELECT * FROM tb_game WHERE price > 50 ORDER BY price DESC LIMIT ?, ?";
PreparedStatement ps = conn.preparedStatement(sql);
// 賦值
ps.setInt(1, (currentPage - 1) * pageSize);
ps.setInt(2, pageSize);
ResultSet rs = ps.executeQuery();

與此同時,還需要計算獲取的資料的總記錄數,用於計算分頁的總頁數,便於前端傳遞是要哪一頁的資料給後端。

int count = 0;
String sql = "SELECT COUNT(*) FROM tb_game WHERE price > 50";
PreparedStatement ps = conn.preparedStatement(sql);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
    // 獲取總記錄數,getInt(1) 是獲取第一列的資料
    count = rs.getInt(1);
}

總結

目前在 Java 中透過 JDBC 來運算元據庫,就有幾個固定的步驟,先載入資料庫驅動程式,接著獲取資料庫的連線,有了這個連線後,才能進行 CRUD 的操作,操作後也可以獲取操作的結果,最後關閉這些資源,比如資料庫連線。

不過,在日常的開發中,基本不會用到原生的 JDBC 來運算元據庫,一般我們有多種選擇,可以使用 JdbcTemplate、Hibernate、MyBatis、JPA(Java Persistence API,Java 持久化 API)或者是其他任意的持久化框架。

最後的最後

由本人水平所限,難免有錯誤以及不足之處, 螢幕前的靚仔靚女們 如有發現,懇請指出!

最後,謝謝你看到這裡,謝謝你認真對待我的努力,希望這篇部落格對你有所幫助!

你輕輕地點了個贊,那將在我的心裡世界增添一顆明亮而耀眼的星!