2013-05-31 26 views
5

Trong ứng dụng của chúng tôi, chúng tôi đang sử dụng Spring và Hibernate.Tiêm đối tượng phiên vào DAO bean thay vì Session Factory?

Trong tất cả các lớp DAO, chúng tôi có tự động SessionFactory có dây và mỗi phương thức DAO đang gọi phương thức getCurrentSession().

Câu hỏi Tôi có lý do tại sao chúng ta không tiêm đối tượng Session thay vì đối tượng SessionFactory trong phạm vi nguyên mẫu? Điều này sẽ tiết kiệm cho chúng tôi cuộc gọi đến getCurrentSession.

Tôi nghĩ phương pháp đầu tiên là chính xác nhưng tìm kiếm các tình huống cụ thể mà phương pháp thứ hai sẽ ném lỗi hoặc có thể có hiệu suất kém?

+0

Một trường hợp đã đọc [doc] (http://docs.jboss.org/hibernate/orm/3.5/javadoc/org/hibernate/Session.html) có nội dung 'Nếu Session có ngoại lệ, giao dịch phải được khôi phục và phiên bị hủy. Trạng thái bên trong của phiên có thể không nhất quán với cơ sở dữ liệu sau khi ngoại lệ xảy ra.' –

+0

Bạn nên tiêm 'javax.persistence.EntityManager' nhưng vì điều đó, bạn phải nhấn mạnh khi sử dụng JPA thay thế. – Lion

Trả lời

3

Khi bạn xác định một bean làm phạm vi mẫu thử nghiệm, một cá thể mới được tạo cho mỗi vị trí cần được chèn vào. Vì vậy, mỗi DAO sẽ nhận được một phiên bản khác nhau của phiên, nhưng tất cả các invocations của các phương pháp trên DAO sẽ kết thúc bằng cách sử dụng cùng một phiên. Vì phiên không phải là chủ đề an toàn nên nó không được chia sẻ trên nhiều luồng, đây sẽ là một vấn đề.

Đối với hầu hết các trường hợp, phiên phải là phạm vi giao dịch, nghĩa là phiên mới được mở khi giao dịch bắt đầu và sau đó được đóng tự động sau khi giao dịch kết thúc. Trong một vài trường hợp, nó có thể phải được mở rộng để yêu cầu phạm vi.

Nếu bạn muốn tránh sử dụng SessionFactory.currentSession - thì bạn sẽ cần phải xác định triển khai phạm vi của riêng bạn để đạt được điều đó.

Đây là thứ đã được triển khai cho JPA sử dụng proxy. Trong trường hợp JPA EntityManager được tiêm thay vì EntityManagerFactory. Thay vì @Autowired, có một chú thích @PersistenceContext mới. Một proxy được tạo ra và được tiêm trong khi khởi tạo. Khi bất kỳ phương thức nào được gọi, proxy sẽ nhận được thực thi EntityManager thực tế (sử dụng một cái gì đó tương tự như SessionFactory.getCurrentSession) và ủy quyền cho nó.

Điều tương tự cũng có thể được triển khai cho Hibernate, nhưng độ phức tạp bổ sung không đáng giá. Nó đơn giản hơn nhiều để định nghĩa một phương thức getSession trong một BaseDAO gọi nội bộ SessionFactory.getCurrentSession(). Với mã này sử dụng phiên là giống hệt với phiên tiêm.

3

Tiêm phiên nguyên mẫu có nghĩa là mỗi đối tượng DAO của bạn, theo định nghĩa, có phiên riêng ... Mặt khác, SessionFactory cấp cho bạn quyền open và chia sẻ theo ý muốn.

Thực tế, getCurrentSession sẽ không mở Phiên mới trên mọi cuộc gọi ... Thay vào đó, nó sẽ sử dụng lại phiên được liên kết với current session context (ví dụ: Chủ đề, JTA Transacion hoặc Ngữ cảnh được quản lý bên ngoài).

Vì vậy, hãy nghĩ về nó; giả sử rằng trong lớp nghiệp vụ của bạn có một hoạt động cần đọc và cập nhật một số bảng cơ sở dữ liệu (có nghĩa là tương tác, trực tiếp hoặc gián tiếp, với một số DAO) ... Kịch bản khá phổ biến đúng không? Thông thường khi loại hoạt động này không thành công, bạn sẽ muốn khôi phục mọi thứ đã xảy ra trong hoạt động hiện tại đúng không? Vì vậy, đối với trường hợp "cụ thể" này, loại chiến lược nào có vẻ phù hợp?

  1. Mở rộng một vài phiên, mỗi phiên quản lý loại đối tượng riêng của mình và ràng buộc với các giao dịch khác nhau.
  2. Có một phiên duy nhất quản lý các đối tượng liên quan đến hoạt động này ... Phân định các giao dịch theo nhu cầu kinh doanh của bạn.

Tóm lại, chia sẻ phiên và phân định giao dịch hiệu quả sẽ không chỉ cải thiện hiệu suất ứng dụng của bạn, nó là một phần của chức năng của ứng dụng của bạn.

Tôi rất muốn giới thiệu bạn đọc Chapter 2Chapter 13 của Hibernate Core Reference Manual để hiểu rõ hơn về vai trò mà SessionFactory, SessionTransaction lượt trong khuôn khổ. Nó cũng sẽ dạy về Đơn vị công việc cũng như các mẫu phiên phổ biến và chống mẫu.

Các vấn đề liên quan