Đó không phải là lỗi của PDO, đó là lỗi vốn có trong quản lý giao dịch của PostgreSQL. Xem:
- Làm cách nào để yêu cầu PostgreSQL không hủy bỏ toàn bộ giao dịch khi một ràng buộc duy nhất bị lỗi?
- Tôi có thể yêu cầu Postgresql bỏ qua lỗi trong giao dịch không
- Khôi phục sau lỗi trong giao dịch
PostgreSQL không khôi phục giao dịch, nhưng nó đặt nó thành trạng thái bị hủy bỏ, nơi nó chỉ có thể khôi phục và tất cả các câu lệnh ngoại trừ ROLLBACK
báo lỗi:
(Tôi rất ngạc nhiên khi không thấy điều này được đề cập trong tài liệu chính thức; tôi nghĩ rằng tôi sẽ cần viết một bản vá để cải thiện điều đó.)
Vì thế. Khi bạn thử / bắt và nuốt ngoại lệ trong PDO, bạn đang mắc kẹt một ngoại lệ phía PHP, nhưng bạn sẽ không thay đổi thực tế là giao dịch PostgreSQL đang ở trạng thái bị hủy bỏ.
Nếu bạn muốn có thể nuốt các ngoại lệ và tiếp tục sử dụng giao dịch, bạn phải tạo SAVEPOINT
trước mỗi câu lệnh có thể bị lỗi. Nếu không thành công, bạn phải ROLLBACK TO SAVEPOINT ...;
. Nếu thành công, bạn có thể RELEASE SAVEPOINT ...;
. Điều này đặt ra thêm chi phí cho cơ sở dữ liệu để quản lý giao dịch, thêm các chuyến đi khứ hồi và ghi thông qua các ID giao dịch nhanh hơn (có nghĩa là PostgreSQL phải thực hiện nhiều công việc dọn dẹp nền hơn).
Thay vào đó, bạn nên thiết kế SQL của mình để nó không bị lỗi trong những trường hợp bình thường. Ví dụ:bạn có thể xác thực hầu hết các ràng buộc phía máy khách, coi các ràng buộc phía máy chủ như một cấp độ đảm bảo thứ hai trong khi vẫn bẫy hầu hết các lỗi ở phía máy khách.
Nếu điều đó là không thực tế, hãy làm cho ứng dụng của bạn có khả năng chịu lỗi để ứng dụng có thể thử lại một giao dịch không thành công. Đôi khi, điều này vẫn cần thiết - ví dụ, bạn không thể sử dụng các điểm lưu để khôi phục sau khi ngừng giao dịch bế tắc hoặc thất bại tuần tự hóa. Nó cũng có thể hữu ích khi giữ các giao dịch dễ xảy ra thất bại càng ngắn càng tốt, chỉ thực hiện công việc tối thiểu được yêu cầu, do đó bạn ít phải theo dõi và lặp lại hơn.
Vì vậy:Nếu có thể, thay vì nuốt một ngoại lệ, hãy chạy mã cơ sở dữ liệu dễ bị lỗi trong một vòng lặp thử lại. Đảm bảo mã của bạn lưu giữ bản ghi thông tin cần thiết để thử lại toàn bộ giao dịch do nhầm lẫn, chứ không chỉ báo cáo gần đây nhất.
Hãy nhớ, bất kỳ giao dịch có thể không thành công:DBA có thể khởi động lại cơ sở dữ liệu để áp dụng bản vá, hệ thống có thể hết RAM do chạy cron job, v.v. Vì vậy, các ứng dụng có khả năng chịu lỗi dù sao cũng là một thiết kế tốt.
Các đạo cụ cho bạn ít nhất là sử dụng các ngoại lệ PDO và xử lý các ngoại lệ - bạn đã đi trước hầu hết các nhà phát triển rồi.