CodeGym /Các khóa học /SQL SELF /Kiểm soát việc thực thi hàm: PERFORM

Kiểm soát việc thực thi hàm: PERFORM

SQL SELF
Mức độ , Bài học
Có sẵn

PERFORM trong thế giới PostgreSQL giống như một anh hùng trầm lặng, đến, làm việc của mình rồi biến mất, không để lại dấu vết gì kiểu dữ liệu trả về. Lệnh này dùng khi bạn muốn chạy một truy vấn SQL trong hàm PL/pgSQL, nhưng không cần xử lý hay lưu kết quả. Nhiệm vụ chính của PERFORM là gọi truy vấn để có điều gì đó xảy ra, ví dụ như sửa đổi dữ liệu hoặc gọi hàm khác, chứ không phải lấy kết quả về.

PERFORM dùng trong trường hợp bạn không quan tâm đến kết quả truy vấn. Khác với SELECT thông thường, vốn đòi hỏi bạn phải làm gì đó với kết quả, PERFORM chỉ chạy truy vấn rồi lặng lẽ đi tiếp. Cực kỳ tiện nếu bạn gọi hàm chỉ để nó thực hiện hành động nào đó, chứ không phải vì giá trị trả về. Ví dụ, ghi log. Cách này làm code gọn hơn, dễ hiểu hơn: ít rườm rà, nhiều ý nghĩa.

Ví dụ sử dụng PERFORM

Gọi hàm

Cùng xem ví dụ thực tế nhé. Giả sử bạn có hàm log_action để ghi thông tin hành động của user vào log. Hàm này không trả về gì, và bạn chỉ muốn nó chạy thôi. Đây là cách dùng PERFORM:

CREATE OR REPLACE FUNCTION log_action(user_id INT, action TEXT) RETURNS VOID AS $$
BEGIN
    INSERT INTO logs (user_id, action, log_time)
    VALUES (user_id, action, NOW());
END;
$$ LANGUAGE plpgsql;

-- Tiếp theo dùng PERFORM để gọi hàm này:
PERFORM log_action(5, 'Người dùng đã đăng nhập');

Ở đây có gì? Lệnh PERFORM gọi hàm log_action, hàm này ghi một dòng vào bảng logs. Bạn nhớ nhé: kết quả trả về của hàm bị bỏ qua. Mình dùng nó chỉ vì hiệu ứng phụ, không phải vì giá trị trả về.

Cập nhật dữ liệu

Đôi khi PERFORM hữu ích khi bạn cần chạy truy vấn để thay đổi dữ liệu mà không quan tâm đến kết quả. Ví dụ, cập nhật trạng thái đơn hàng trong bảng orders.

CREATE OR REPLACE FUNCTION update_order_status(order_id INT, new_status TEXT) RETURNS VOID AS $$
BEGIN
    UPDATE orders
    SET status = new_status
    WHERE id = order_id;
END;
$$ LANGUAGE plpgsql;

-- Dùng PERFORM để gọi hàm này:
PERFORM update_order_status(101, 'Đã gửi hàng');

Ở đây update_order_status cập nhật trạng thái đơn hàng có id 101. Mình không quan tâm đến kết quả truy vấn SQL trong hàm, nên PERFORM là lựa chọn hoàn hảo.

Chạy thao tác phụ trợ

Đôi khi hàm chứa các thao tác nhỏ kiểu "phụ trợ", giúp hoàn thành một quy trình phức tạp. Ví dụ, bạn muốn xóa cache sau khi cập nhật bảng:

CREATE OR REPLACE FUNCTION clear_cache() RETURNS VOID AS $$
BEGIN
    DELETE FROM cache_table;
END;
$$ LANGUAGE plpgsql;

-- Gọi nó trong hàm khác:
CREATE OR REPLACE FUNCTION update_product(product_id INT, new_price NUMERIC) RETURNS VOID AS $$
BEGIN
    UPDATE products
    SET price = new_price
    WHERE id = product_id;

    -- Xóa cache sau khi thay đổi dữ liệu:
    PERFORM clear_cache();
END;
$$ LANGUAGE plpgsql;

Đây là chỗ hay ho: bạn có thể thực hiện liên tiếp các hành động, dùng PERFORM để gọi hàm mà bạn hoàn toàn không cần kết quả trả về.

Bài tập thực tế

Cùng xem vài ví dụ về cách PERFORM giúp dev đỡ cực hơn nhé.

Ví dụ 1: ghi log các bước thực hiện thủ tục

Giả sử bạn có một thủ tục xử lý thanh toán phức tạp, cần theo dõi từng giai đoạn và ghi log lại. Bạn có thể định nghĩa hàm log_stage để ghi thông tin, rồi dùng PERFORM:

CREATE OR REPLACE FUNCTION log_stage(stage_name TEXT) RETURNS VOID AS $$
BEGIN
    INSERT INTO process_logs(stage, log_time)
    VALUES (stage_name, NOW());
END;
$$ LANGUAGE plpgsql;

-- Đây là ví dụ thủ tục:
CREATE OR REPLACE FUNCTION process_payment(payment_id INT) RETURNS VOID AS $$
BEGIN
    -- Ghi log bắt đầu
    PERFORM log_stage('Bắt đầu xử lý thanh toán');

    -- Thực hiện bước đầu tiên
    UPDATE payments
    SET status = 'Đang xử lý'
    WHERE id = payment_id;

    PERFORM log_stage('Đã cập nhật trạng thái thanh toán');

    -- Thực hiện bước cuối
    UPDATE payments
    SET status = 'Hoàn thành'
    WHERE id = payment_id;

    PERFORM log_stage('Đã hoàn thành thanh toán');
END;
$$ LANGUAGE plpgsql;

Ở đây log_stage được gọi qua PERFORM để ghi trạng thái thực hiện ở mỗi bước của thủ tục. Nhờ vậy code dễ debug hơn nhiều.

Ví dụ 2: kích hoạt thông báo

Giả sử bạn có hệ thống thông báo, cần gửi thông báo sau mỗi hành động quan trọng. PERFORM có thể dùng để gọi hàm phụ trách việc này:

CREATE OR REPLACE FUNCTION send_notification(user_id INT, message TEXT) RETURNS VOID AS $$
BEGIN
    INSERT INTO notifications (user_id, message, created_at)
    VALUES (user_id, message, NOW());
END;
$$ LANGUAGE plpgsql;

-- Dùng trong thủ tục:
CREATE OR REPLACE FUNCTION complete_task(task_id INT) RETURNS VOID AS $$
DECLARE
    user_id INT;
BEGIN
    -- Lấy tác giả task
    SELECT assigned_to INTO user_id
    FROM tasks
    WHERE id = task_id;

    -- Hoàn thành task
    UPDATE tasks
    SET status = 'Hoàn thành'
    WHERE id = task_id;

    -- Gửi thông báo
    PERFORM send_notification(user_id, 'Nhiệm vụ của bạn đã hoàn thành');
END;
$$ LANGUAGE plpgsql;

Ở đây PERFORM giúp bạn chỉ tập trung vào hiệu ứng phụ - gửi thông báo, bỏ qua kết quả thực thi của hàm.

Tips hữu ích và lỗi thường gặp

Khi dùng PERFORM, nhớ một số điểm quan trọng. Ví dụ, PERFORM không kiểm tra xem truy vấn có trả về dữ liệu không. Nghĩa là nếu kết quả của hàm hoặc truy vấn SQL quan trọng cho logic, tốt nhất nên dùng SELECT INTO. Xem ví dụ nhé:

-- Lỗi tiềm ẩn
PERFORM some_function_that_must_return_value();

-- Sửa đúng
SELECT some_function_that_must_return_value() INTO some_variable;

Một lỗi phổ biến nữa là dùng PERFORM ở chỗ bạn thực sự cần lấy kết quả truy vấn, ví dụ kiểm tra dữ liệu. Trong trường hợp đó, tất nhiên nên lấy kết quả và kiểm tra nó.

Trong dự án thực tế, lệnh PERFORM giúp hàm và thủ tục đơn giản, dễ đọc và dễ debug hơn. Kết hợp với ghi log (RAISE NOTICE) và các hàm chẩn đoán tích hợp của PostgreSQL như current_query(), nó trở thành công cụ quan trọng để xây dựng hệ thống ổn định, dễ kiểm soát và dễ hiểu.

Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION