0

JDBC bài 9 Kỹ thuật Update: Cập nhật bản ghi và kiểm soát số lượng dòng bị ảnh hưởng (Affected Rows)

Sau khi đã thêm (Create) và đọc (Read) dữ liệu, thao tác tiếp theo cực kỳ quan trọng trong vòng đời CRUD chính là cập nhật (Update). Dù là đổi mật khẩu, thay đổi trạng thái đơn hàng hay cập nhật thông tin cá nhân, chúng ta đều sử dụng lệnh UPDATE trong SQL kết hợp với phương thức executeUpdate() của JDBC.

1. Bản chất của executeUpdate() trong lệnh UPDATE

Như đã đề cập ở Bài 6, phương thức stmt.executeUpdate(sql) được thiết kế dùng chung cho cả ba thao tác DML (INSERT, UPDATE, DELETE). Đặc điểm cốt lõi của phương thức này là nó trả về một số nguyên (int).

Con số này không phải là dữ liệu của Database, mà nó đại diện cho Affected Rows (Số lượng dòng bị ảnh hưởng/thay đổi bởi câu lệnh SQL).

  • Nếu bạn cập nhật 1 khách hàng, nó trả về 1.

  • Nếu bạn cập nhật trạng thái cho 50 đơn hàng cùng lúc, nó trả về 50.

  • Nếu không có dòng nào thỏa mãn điều kiện cập nhật, nó trả về 0.

2. Tại sao "Affected Rows" lại đóng vai trò quyết định trong Backend?

Trong môi trường lập trình Backend thực tế (như khi bạn xây dựng RESTful API), giá trị Affected Rows chính là "cây gậy dò đường" để bạn quyết định luồng xử lý tiếp theo (Business Logic).

Giả sử hệ thống nhận được yêu cầu: "Cập nhật trạng thái đơn hàng ID = 999 thành 'Đã giao'". Khi chạy lệnh UPDATE, Database sẽ không văng lỗi (Exception) nếu đơn hàng số 999 không tồn tại; nó chỉ đơn giản là thực thi thành công và báo lại rằng có 0 dòng bị ảnh hưởng.

Dựa vào con số này, người kỹ sư Backend mới quyết định được mã phản hồi:

  • Affected Rows > 0: Cập nhật thành công (Trân trọng trả về HTTP Status 200 OK).

  • Affected Rows == 0: Không tìm thấy dữ liệu để cập nhật (Phải trả về HTTP Status 404 Not Found, hoặc báo lỗi cho người dùng).

3. Thực hành: Cập nhật trạng thái đơn hàng và kiểm soát logic

Dưới đây là một ví dụ thực tế mô phỏng quá trình cập nhật trạng thái của một đơn hàng trong cơ sở dữ liệu shop_db.

Java

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class UpdateExample {
    private static final String URL = "jdbc:mysql://localhost:3306/shop_db";
    private static final String USER = "root";
    private static final String PASSWORD = "password123";

    public static void main(String[] args) {
        
        // Giả sử chúng ta muốn cập nhật trạng thái cho đơn hàng có ID = 100
        int targetOrderId = 100;
        String newStatus = "DELIVERED";
        
        // Câu lệnh SQL (Vẫn đang dùng chuỗi tĩnh, bài sau chúng ta sẽ tối ưu bằng PreparedStatement)
        String updateSQL = "UPDATE orders SET status = '" + newStatus + "' WHERE id = " + targetOrderId;

        try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
             Statement stmt = conn.createStatement()) {

            System.out.println("Đang thực thi lệnh cập nhật...");
            
            // Lấy về số dòng bị ảnh hưởng
            int affectedRows = stmt.executeUpdate(updateSQL);
            
            // Xử lý Business Logic dựa trên affectedRows
            if (affectedRows > 0) {
                System.out.println("Tuyệt vời, Hiếu! Đã cập nhật thành công trạng thái cho " + affectedRows + " đơn hàng.");
                // Thực hiện tiếp các tác vụ như gửi email thông báo, gọi service hệ thống ERP...
            } else {
                System.out.println("Cảnh báo: Không tìm thấy đơn hàng ID = " + targetOrderId + " để cập nhật.");
                // Ném ra một custom exception hoặc trả về response 404 Not Found
            }

        } catch (SQLException e) {
            System.err.println("Lỗi cơ sở dữ liệu: " + e.getMessage());
        }
    }
}

4. Lưu ý sống còn (Data Disaster Warning)

Quy tắc bất di bất dịch khi làm việc với UPDATE (và cả DELETE sau này): LUÔN LUÔN KIỂM TRA MỆNH ĐỀ WHERE.

Nếu bạn lỡ tay viết một câu lệnh: String updateSQL = "UPDATE orders SET status = 'DELIVERED'"; (Quên mất mệnh đề WHERE ở cuối).

JDBC và Database sẽ răm rắp nghe lời bạn. Lệnh executeUpdate sẽ chạy trơn tru, không ném ra bất kỳ SQLException nào. Kết quả trả về sẽ là 150,000 (giả sử bảng có 150 ngàn dòng), đồng nghĩa với việc toàn bộ hệ thống đơn hàng của công ty đã bị đổi sạch thành trạng thái 'DELIVERED'. Đây là một trong những sự cố tồi tệ nhất có thể xảy ra ở tầng Data Access.

Việc kiểm soát chặt chẽ giá trị của affectedRows (ví dụ: kỳ vọng cập nhật 1 dòng nhưng affectedRows trả về > 1) cũng là một chốt chặn phụ giúp bạn phát hiện ra những câu SQL đang viết sai logic để kịp thời rollback (sẽ học kỹ ở Phần quản lý Transaction).


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí