2009-07-08 23 views
216

Tôi muốn biết điều gì thực sự xảy ra khi bạn chú thích một phương thức với @Transactional? Tất nhiên, tôi biết rằng Spring sẽ bao bọc phương thức đó trong một giao dịch.Mùa xuân - @Transactional - Điều gì xảy ra ở chế độ nền?

Nhưng, tôi có những nghi ngờ sau:

  1. Tôi nghe nói rằng mùa xuân sẽ tạo ra một lớp Proxy? Ai đó có thể giải thích điều này ở nhiều hơn độ sâu. Điều gì thực sự nằm trong lớp proxy đó? Điều gì sẽ xảy ra với lớp học thực tế? Và làm thế nào tôi có thể thấy được tạo ra lớp proxy Spring
  2. Tôi cũng đọc trong tài liệu Xuân rằng:

Lưu ý: Kể từ khi cơ chế này được dựa trên proxy, chỉ phương pháp 'bên ngoài' cuộc gọi đến trong thông qua proxy sẽ bị chặn. Điều này có nghĩa là 'tự viện dẫn', tức là một phương thức trong đối tượng đích gọi một số phương thức khác của đối tượng đích, sẽ không dẫn đến giao dịch thực sự trong thời gian chạy ngay cả khi phương thức được gọi được đánh dấu bằng @Transactional!

Nguồn: http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html

Tại sao cuộc gọi phương thức bên ngoài chỉ sẽ chịu giao dịch và không phải là phương pháp tự gọi?

+1

Thảo luận có liên quan ở đây: http://stackoverflow.com/questions/3120143/where-should-i-put-transactional-annotation-at-an-interface-definition-or-at-an/3120323#3120323 –

Trả lời

168

Đây là một chủ đề lớn. Tài liệu tham khảo Spring dành nhiều chương cho nó. Tôi khuyên bạn nên đọc những cái trên Aspect-Oriented ProgrammingTransactions, vì hỗ trợ giao dịch khai báo của Spring sử dụng AOP tại nền tảng của nó.

Nhưng ở cấp độ rất cao, Spring tạo proxy cho các lớp khai báo @Transactional trên chính lớp hoặc trên các thành viên. Proxy chủ yếu là vô hình trong thời gian chạy. Nó cung cấp một cách để Spring tiêm các hành vi trước, sau hoặc xung quanh các cuộc gọi phương thức vào đối tượng đang được ủy quyền. Quản lý giao dịch chỉ là một ví dụ về các hành vi có thể được nối vào. Kiểm tra bảo mật là một ví dụ khác. Và bạn cũng có thể tự cung cấp cho những thứ như đăng nhập. Vì vậy, khi bạn chú thích một phương thức với @Transactional, Spring tự động tạo proxy để triển khai cùng (các) giao diện giống như lớp bạn đang chú thích. Và khi khách hàng thực hiện cuộc gọi vào đối tượng của bạn, các cuộc gọi bị chặn và các hành vi được tiêm qua cơ chế proxy.

Giao dịch trong EJB hoạt động tương tự, nhân tiện.

Khi bạn quan sát, thông qua, cơ chế proxy chỉ hoạt động khi có cuộc gọi đến từ một số đối tượng bên ngoài. Khi bạn thực hiện cuộc gọi nội bộ trong đối tượng, bạn thực sự đang thực hiện cuộc gọi thông qua tham chiếu "" "này, bỏ qua proxy. Tuy nhiên, có nhiều cách để giải quyết vấn đề đó. Tôi giải thích một cách tiếp cận trong this forum post trong đó tôi sử dụng BeanFactoryPostProcessor để tiêm một cá thể của proxy vào các lớp "tự tham khảo" khi chạy. Tôi lưu tham chiếu này vào biến thành viên có tên "me". Sau đó, nếu tôi cần thực hiện cuộc gọi nội bộ yêu cầu thay đổi trạng thái giao dịch của luồng, tôi chỉ đạo cuộc gọi thông qua proxy (ví dụ: "me.someMethod()".) Bài diễn đàn giải thích chi tiết hơn. Lưu ý rằng mã BeanFactoryPostProcessor sẽ hơi khác một chút, vì nó được viết lại trong khung thời gian Spring 1.x. Nhưng hy vọng nó mang lại cho bạn một ý tưởng. Tôi có một phiên bản cập nhật mà tôi có thể làm cho có sẵn.

+1

>> Proxy chủ yếu là vô hình trong thời gian chạy Oh !! Tôi tò mò muốn xem chúng :) Phần còn lại .. câu trả lời của bạn rất toàn diện. Đây là lần thứ hai bạn đang giúp tôi .. Cảm ơn tất cả sự giúp đỡ. – peakit

+9

Không sao cả. Bạn có thể thấy mã proxy nếu bạn duyệt qua một trình gỡ lỗi. Đó có lẽ là cách dễ nhất. Không có phép thuật; chúng chỉ là các lớp trong các gói Spring. –

+0

Và nếu phương thức có chú thích @Transaction đang triển khai giao diện thì mùa xuân sẽ sử dụng API proxy động để tiêm giao tác và _not_ sử dụng proxy. Tôi thích có các lớp giao dịch của tôi thực hiện các giao diện trong mọi trường hợp. –

139

Khi Spring tải định nghĩa bean của bạn và đã được cấu hình để tìm chú thích @Transactional, nó sẽ tạo các đối tượng proxy này quanh bean thực của bạn. Các đối tượng proxy này là các cá thể của các lớp được tạo tự động khi chạy. Hành vi mặc định của các đối tượng proxy này khi một phương thức được gọi là chỉ để gọi phương thức tương tự trên bean "target" (nghĩa là bean của bạn).

Tuy nhiên, các proxy cũng có thể được cung cấp với bộ chặn và khi trình bày các bộ chặn này sẽ được proxy gọi ra trước khi nó gọi phương thức của bean mục tiêu của bạn. Đối với các bean mục tiêu được chú thích bằng @Transactional, Spring sẽ tạo một TransactionInterceptor và chuyển nó tới đối tượng proxy đã tạo. Vì vậy, khi bạn gọi phương thức từ mã máy khách, bạn đang gọi phương thức trên đối tượng proxy, lần đầu tiên gọi TransactionInterceptor (bắt đầu một giao dịch), mà lần lượt gọi phương thức trên bean mục tiêu của bạn. Khi lời gọi kết thúc, TransactionInterceptor cam kết/cuộn lại giao dịch. Đó là minh bạch cho mã khách hàng.

Đối với phương thức "phương thức bên ngoài", nếu bean của bạn gọi một trong các phương thức riêng của nó, thì nó sẽ không làm như vậy thông qua proxy. Hãy nhớ rằng, Spring kết thúc tốt đẹp bean của bạn trong proxy, bean của bạn không có kiến ​​thức về nó. Chỉ có cuộc gọi từ "bên ngoài" đậu của bạn đi qua proxy.

Điều đó có hữu ích không?

+20

> Hãy nhớ rằng, Spring kết thúc bean của bạn trong proxy, bean của bạn không có kiến ​​thức về nó ** Điều này nói lên tất cả. Thật là một câu trả lời tuyệt vời. Cảm ơn bạn đã trợ giúp. ** – peakit

+0

Giải thích tuyệt vời cho proxy và kẻ đánh chặn. Bây giờ tôi hiểu mùa xuân thực hiện một đối tượng proxy để chặn các cuộc gọi đến một bean mục tiêu. Cảm ơn bạn! – dharag

+5

Câu trả lời là tuyệt vời đến nỗi tôi chỉ cố gắng để upvote nó chỉ được trình bày với một thông báo lỗi mà tôi đã upvoted nó trước! – Mustafa

20

Là người trực quan, tôi muốn cân nhắc với biểu đồ trình tự của mẫu proxy. Nếu bạn không biết cách đọc mũi tên, tôi đọc phần đầu tiên như sau: Client thực hiện Proxy.method().

  1. Các khách hàng gọi một phương thức trên đối tượng từ góc độ của mình, và được âm thầm chặn bởi proxy
  2. Nếu một khía cạnh trước khi được định nghĩa, proxy sẽ thực hiện nó
  3. Sau đó, phương pháp thực tế (mục tiêu) được thực hiện
  4. sau-trở về và sau khi ném những khía cạnh tùy chọn mà thực hiện sau khi trở về phương pháp và/hoặc nếu phương pháp ném một ngoại lệ
  5. sau đó, proxy thực hiện sau khi khía cạnh (nếu định nghĩa)
  6. Cuối cùng trở về proxy để khách hàng gọi điện thoại

Proxy Pattern Sequence Diagram (tôi được phép đăng các bức ảnh với điều kiện là tôi đã đề cập nguồn gốc của nó. Tác giả: Noel Vaes, trang web: www.noelvaes.eu)

0

Câu trả lời đơn giản nhất là, trên phương thức nào bạn khai báo @Transactional ranh giới bắt đầu giao dịch và kết thúc ranh giới khi phương thức hoàn thành.

Nếu bạn đang sử dụng cuộc gọi JPA thì tất cả các cam kết có trong ranh giới giao dịch này. Cho phép nói rằng bạn đang lưu entity1, entity2 và entity3. Bây giờ trong khi lưu entity3 một ngoại lệ xảy ra sau đó là enitiy1 và entity2 đến trong cùng một giao dịch để thực thể1 và entity2 sẽ được rollback với entity3.

Giao dịch: (entity1.save, entity2.save, entity3.save). Bất kỳ ngoại lệ nào cũng sẽ dẫn đến việc khôi phục tất cả các giao dịch JPA với DB. Giao dịch JPA nội bộ được Spring sử dụng.

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