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

god23bin發表於2023-03-18

前言

資料庫的重要性不言而喻,不管是什麼系統,什麼應用軟體,也不管它們是 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)或者是其他任意的持久化框架。

最後的最後

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

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

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