Spring @Transactional: self-invocation, propagation và rollback có những bẫy nào?

Đang tìm đáp án

29 lượt xem · 4 trả lời

Cộng đồng đang cùng tìm lời giải

Người đặt câu hỏi có thể chọn câu trả lời hữu ích nhất làm đáp án.

1. 12:37 06/08/2026
Chào admin, Mình có method được gắn @Transactional nhưng khi một method khác trong cùng class gọi nó thì transaction dường như không hoạt động như mong đợi. Ngoài ra mình chưa tự tin khi chọn propagation và khi nào exception sẽ rollback. Admin có thể giải thích cách thiết kế service để transaction rõ ràng và dễ test không?
0 Facebook
2. 12:38 06/08/2026
Chào bạn Ngọc Diệp, @Transactional của Spring thường hoạt động qua proxy, vì vậy self-invocation trong cùng instance sẽ không đi qua proxy và có thể bỏ qua interceptor transaction. Cách tốt hơn là đặt ranh giới transaction ở public method của service use case, hoặc tách operation cần transaction khác sang bean riêng thay vì tìm cách gọi vòng qua chính mình. Propagation mặc định REQUIRED phù hợp cho nhiều use case; chỉ dùng REQUIRES_NEW hoặc các mode khác khi bạn hiểu rõ tác động về tính nhất quán và lock. Theo mặc định, runtime exception sẽ rollback, còn checked exception cần cấu hình rollbackFor nếu muốn rollback. Giữ transaction ngắn, không gọi remote service bên trong transaction dài, hiểu isolation của database và viết integration test kiểm tra commit/rollback cho các nhánh lỗi quan trọng.
0
3. 08:14 12/10/2026
Trả lời Ngọc Diệp Chào admin, Mình có method được gắn @Transactional nhưng khi một method khác trong cùng class gọi nó thì transaction dườ…
Vấn đề self-invocation xảy ra vì Spring dùng proxy: gọi method nội bộ (`this.method()`) bỏ qua proxy nên `@Transactional` không kích hoạt. Giải pháp thực tế phổ biến là tách method cần transaction ra một `@Service` riêng (ví dụ `OrderService` gọi `PaymentService`) hoặc dùng `ApplicationContext` inject self (ít khuyến khích vì tạo phụ thuộc vòng). Về propagation: mặc định `REQUIRED` phù hợp đa số case nghiệp vụ đơn giản. Chỉ dùng `REQUIRES_NEW` khi cần ghi log/audit độc lập dù transaction cha rollback, hoặc `NESTED` (hỗ trợ bởi DataSourceTransactionManager) để rollback riêng một đoạn logic con mà không ảnh hưởng cha. Rollback mặc định chỉ xảy ra với `RuntimeException` và `Error`. Checked exception thì không rollback trừ khi cấu hình `@Transactional(rollbackFor = Exception.class)` hoặc chỉ định loại cụ thể. Để test dễ dàng, hãy thiết kế service theo interface, tiêm dependency qua constructor, và dùng `@Transactional` ở lớp triển khai (implementation) chứ không phải interface. Integration test với `@SpringBootTest` + `@Transactional` (mặc định rollback sau test) là cách an toàn nhất. Mình thấy bạn đang xử lý case nào cụ thể: gọi đệ quy trong cùng service, hay cần tách transaction cho ghi log/notification?
0
4. 16:35 13/10/2026
Trả lời Ngọc Diệp Chào admin, Mình có method được gắn @Transactional nhưng khi một method khác trong cùng class gọi nó thì transaction dườ…
Vấn đề "self-invocation" xảy ra vì Spring dùng proxy: khi method A gọi method B trong cùng class, lời gọi đi thẳng vào bytecode thay vì qua proxy, nên @Transactional trên B bị bỏ qua. Giải pháp phổ biến nhất là tách method cần transaction ra một bean riêng (Service khác) và inject vào, hoặc dùng `ApplicationContext`/`AopContext.currentProxy()` (cần bật `expose-proxy=true`) để tự gọi qua proxy — cách sau ít khuyến khích vì tạo phụ thuộc vào AOP runtime. Về propagation: `REQUIRED` (mặc định) đủ cho 90% trường hợp; chỉ dùng `REQUIRES_NEW` khi thực sự cần commit/rollback độc lập (ví dụ ghi log audit dù transaction cha rollback). Lưu ý `REQUIRES_NEW` tốn thêm connection và dễ gây deadlock nếu không cẩn thận. Rollback mặc định chỉ xảy ra với unchecked exception (`RuntimeException`, `Error`). Muốn rollback cả checked exception thì khai báo `@Transactional(rollbackFor = Exception.class)` hoặc liệt kê kiểu cụ thể. Để test dễ dàng: thiết kế service theo interface, tiêm dependency qua constructor, tránh logic phức tạp trong method transactional — tách validation, mapping ra ngoài. Khi test dùng `@DataJpaTest` hoặc `@SpringBootTest` kèm `@Transactional` trên test method để tự rollback sau mỗi case. Bạn đang xử lý case nào cần `REQUIRES_NEW` hay chỉ lo self-invocation thôi?
0
5. 21:47 25/10/2026
Trả lời Ngọc Diệp Chào admin, Mình có method được gắn @Transactional nhưng khi một method khác trong cùng class gọi nó thì transaction dườ…
Đây đúng là bẫy self-invocation: khi method trong cùng class gọi trực tiếp method có @Transactional, lời gọi
0
Vui lòng đăng nhập để tham gia trả lời chủ đề này.
Điều hướng nhanh

Bạn muốn khám phá điều gì?

Tìm chủ đề, bài viết hoặc đi thẳng đến một khu vực của cộng đồng.

Esc để đóng Ctrl K để mở lại