Tôi đọc một chút về cách thiết lập giao dịch cho dây Spring và Hibernate cùng nhau. Có vẻ cách tiếp cận được khuyến nghị là khởi tạo các giao dịch trong tầng dịch vụ.
Chắc chắn. ranh giới giao dịch phải được thực hiện ở cấp lớp dịch vụ, chứ không phải ở cấp lớp DAO:
- đơn vị làm việc là dịch vụ, không phải là DAO
- bạn muốn có một giao dịch để span nhiều DAO nếu cần thiết.
Điều tôi không thích là hầu hết giao dịch chỉ tồn tại vì chúng được yêu cầu để ngủ đông hoạt động bình thường.
Bạn có thể giải thích phần này vì giao dịch không phải là Hibernate cụ thể.
Và khi tôi thực sự cần một giao dịch cho một công việc gọi nhiều phương thức dịch vụ, có vẻ như tôi không có lựa chọn để tiếp tục khởi tạo giao dịch từ công việc.
Nếu bạn muốn gọi nhiều dịch vụ bên trong một giao dịch bắt đầu từ lớp Job, kê khai dịch vụ của bạn như giao dịch với REQUIRED
ngữ nghĩa (mặc định) và dựa vào tuyên truyền giao dịch mùa xuân (điều này áp dụng trừ khi bạn cần một cuộc gọi từ xa; trong trường hợp đó, hãy sử dụng các EJB).
Vì vậy, di chuyển chú thích @Transactional từ DAO sang dịch vụ dường như không tạo ra bất kỳ sự khác biệt nào.
Nó không tạo sự khác biệt và thực tế mà bạn cần để bắt đầu giao dịch từ lớp Job khi chạy theo lô không làm những điều khác nhau.
Tôi nhiệt liệt khuyên bạn nên đọc Chapter 9. Transaction management.
(...) Vấn đề chính của tôi xuất phát từ Hibernate. Xin lỗi nếu tôi không rõ ràng.
Không sao cả. Chỉ là khi một câu hỏi là mơ hồ, bạn thường nhận được một câu trả lời mơ hồ :)
Từ tài liệu Hibernate: "các giao dịch cơ sở dữ liệu không bao giờ bắt buộc tất cả các thông tin liên lạc với một cơ sở dữ liệu có xảy ra bên trong một giao dịch..". Đó là lý do tại sao các nhà phát triển đưa các phương thức DAO giao dịch vào dự án của tôi.
Xin lỗi nhưng tuyên bố trên chỉ nói rằng "giao tiếp với một cơ sở dữ liệu có xảy ra bên một giao dịch", không có gì hơn, và quyết định để bắt đầu giao dịch nơi còn lại theo ý của bạn (thường là các dịch vụ lớp). Nếu bạn làm điều đó ở cấp DAO, điều gì sẽ xảy ra nếu MySuperService
gọi DaoFoo
và DaoBar
và DaoBar
không thành công? Trong những trường hợp như vậy, có thể bạn sẽ muốn khôi phục tất cả các thay đổi, không chỉ những thay đổi được thực hiện trong DaoBar
. Do đó cần phải kiểm soát giao dịch nơi đơn vị công việc bắt đầu.
IMHO, nhà phát triển cần một số hướng dẫn.
Điều đó có nghĩa là tất cả các dịch vụ của tôi phải được giao dịch? Ngay cả khi tôi chỉ đọc dữ liệu chẳng hạn?
Trước hết, tôi đề nghị để đọc Non-transactional data access and the auto-commit mode (em trai của Sessions and transactions) để làm rõ điều về "read-only giao dịch". Đọc toàn bộ trang là giá trị nó nhưng hãy để tôi chỉ trích dẫn một phần cụ thể này:
Nhiều nhà phát triển ứng dụng nghĩ rằng họ có thể nói chuyện với một cơ sở dữ liệu bên ngoài của một giao dịch . Điều này rõ ràng không phải là có thể; không có câu lệnh SQL nào có thể được gửi tới cơ sở dữ liệu bên ngoài cơ sở dữ liệu giao dịch. Thuật ngữ truy cập dữ liệu không hạn chế nghĩa là không có ranh giới giao dịch rõ ràng, không có giao dịch hệ thống và hành vi truy cập dữ liệu là chế độ tự động . Điều đó không có nghĩa là không có giao dịch cơ sở dữ liệu thực là .
Khi bạn đã hoàn tất với liên kết ở trên, lần đọc được đề xuất tiếp theo sẽ là @Transactional read-only flag pitfalls. Đây là phần có liên quan:
(...) Điểm mấu chốt là khi bạn sử dụng khung dựa trên ORM, cờ chỉ đọc là khá vô dụng và trong hầu hết các trường hợp bị bỏ qua. Nhưng nếu bạn vẫn khăng khăng sử dụng nó, luôn đặt chế độ công tác tuyên truyền để hỗ trợ, như thể hiện trong Liệt kê 9, vì vậy không có giao dịch được bắt đầu:
Liệt kê 9. Sử dụng chỉ đọc và SUPPORTS
chế độ tuyên truyền cho chọn hoạt động
@Transactional(readOnly = true, propagation=Propagation.SUPPORTS)
public TradeData getTrade(long tradeId) throws Exception {
return em.find(TradeData.class, tradeId);
}
Hơn thế nữa, chỉ cần tránh sử dụng các chú thích @Transactional
hoàn toàn khi thực hiện các hoạt động đọc, như.210 trong Liệt kê 10:
Liệt kê 10. Loại bỏ các @Transactional
chú thích cho chọn hoạt động
public TradeData getTrade(long tradeId) throws Exception {
return em.find(TradeData.class, tradeId);
}
xuất sắc câu hỏi và tôi đã định hỏi nó bản thân mình :) – willcodejavaforfood
Giúp với một câu hỏi không phải là vui mừng khi giúp đỡ với một câu trả lời nhưng nó vẫn còn tốt để nghe; o) – Damien