Phương thức @Transactional gọi một phương thức khác mà không có chú thích @Transactional?


89

Tôi đã thấy một phương thức trong lớp Dịch vụ được đánh dấu là @Transactional, nhưng nó cũng đang gọi một số phương thức khác trong cùng lớp đó không được đánh dấu là @Transactional.

Nó có nghĩa là lệnh gọi đến các phương thức riêng biệt đang khiến ứng dụng mở các kết nối riêng biệt tới DB hoặc tạm dừng giao dịch mẹ, v.v.?

Hành vi mặc định cho một phương thức không có bất kỳ chú thích nào được gọi bởi một phương thức khác có @Transactionalchú thích?

Câu trả lời:


117

Khi bạn gọi một phương thức không có @Transactionaltrong một khối giao dịch, giao dịch mẹ sẽ tiếp tục đến phương thức mới. Nó sẽ sử dụng cùng một kết nối từ phương thức mẹ (với @Transactional) và bất kỳ ngoại lệ nào gây ra trong phương thức được gọi (không có @Transactionalsẽ khiến giao dịch quay ngược trở lại như được định cấu hình trong định nghĩa giao dịch.

Nếu bạn gọi một phương thức có @Transactionalchú thích từ một phương thức @Transactionaltrong cùng một trường hợp, thì hành vi giao dịch của các phương thức được gọi sẽ không có bất kỳ tác động nào đến giao dịch. Nhưng nếu bạn gọi một phương thức có định nghĩa giao dịch từ một phương thức khác có định nghĩa giao dịch và chúng ở các trường hợp khác nhau, thì mã trong phương thức được gọi sẽ tuân theo các định nghĩa giao dịch được đưa ra trong phương thức được gọi.

Bạn có thể tìm thêm chi tiết trong phần Quản lý giao dịch khai báo của tài liệu giao dịch mùa xuân .

Mô hình giao dịch khai báo mùa xuân sử dụng proxy AOP. vì vậy proxy AOP chịu trách nhiệm tạo các giao dịch. Proxy AOP sẽ chỉ hoạt động nếu các phương thức trong phiên bản được gọi từ bên ngoài phiên bản.


đó có phải là hành vi mặc định của mùa xuân không?
goe

Đúng. Nó là hành vi mặc định.
Arun P Johny

2
@Tomasz Có. Nhưng cũng cần lưu ý rằng việc thay đổi cách truyền giao dịch trên một phương thức được gọi từ một phương thức @Transactional khác sẽ không có tác dụng.
Fil

1
@Tomasz, Đó là điều tôi muốn nói will follow the transaction definitions given in the called method. Nhưng nếu cuộc gọi đến từ cùng một cá thể đối tượng thì nó sẽ không có bất kỳ ảnh hưởng nào vì cuộc gọi sẽ không truyền qua các proxy aop chịu trách nhiệm duy trì giao dịch.
Arun P Johny

5
@Filip, Điều đó không hoàn toàn chính xác, Nếu bạn gọi một phương thức có @Transactionalđịnh nghĩa từ một đối tượng / thể hiện khác thì ngay cả khi phương thức gọi có các @Transactionalthuộc tính khác , phương thức được gọi sẽ tuân theo định nghĩa giao dịch của chính nó.
Arun P Johny

23
  • Điều đó có nghĩa là lệnh gọi đến các phương thức riêng biệt đang khiến ứng dụng mở các kết nối riêng biệt tới DB hoặc tạm dừng giao dịch mẹ, v.v.?

Điều đó phụ thuộc vào mức độ lan truyền . Đây là tất cả các giá trị mức có thể .

Ví dụ: trong trường hợp mức lan truyền là NESTED, giao dịch hiện tại sẽ "tạm dừng" và giao dịch mới sẽ được tạo ( lưu ý: việc tạo thực tế của giao dịch lồng nhau sẽ chỉ hoạt động trên các trình quản lý giao dịch cụ thể )

  • Hành vi mặc định cho một phương thức không có bất kỳ chú thích nào được gọi bởi một phương thức khác có chú thích @Transactional?

Mức độ lan truyền mặc định (cái mà bạn gọi là "hành vi") là BẮT BUỘC . Trong trường hợp một phương thức "bên trong" được gọi có @Transactionalchú thích trên đó (hoặc được giao dịch một cách khai báo qua XML), nó sẽ thực thi trong cùng một giao dịch , ví dụ: "không có gì mới" được tạo.


Còn các cuộc gọi con NOT_SUPPORTED không có bất kỳ chú thích nào? Nó kế thừa NOT_Supported hay họ đã mở một giao dịch mới vì REQURED là mặc định? Ví dụ: f1.call () {f2 ()} với chú thích NOT_SUPPORTED cho f1 và không cho f2.
Dave

8

@Transactional đánh dấu ranh giới giao dịch (bắt đầu / kết thúc) nhưng bản thân giao dịch bị ràng buộc với chuỗi. Khi một giao dịch bắt đầu, nó sẽ truyền qua các lệnh gọi phương thức cho đến khi phương thức ban đầu quay trở lại và giao dịch cam kết / quay trở lại.

Nếu một phương thức khác được gọi có chú thích @Transactional thì quá trình lan truyền phụ thuộc vào thuộc tính truyền của chú thích đó.


3 câu trả lời mâu thuẫn với nhau ở một mức độ nào đó, không chắc câu trả lời nào chính xác hơn.
Eric Wang

1
@EricWang Chỉ muốn chia sẻ rằng tôi đã thử nghiệm kịch bản này hôm nay và câu trả lời của Arun P Johny (kèm theo bình luận) là chính xác nhất cho kịch bản gọi nội bộ này .
Vinay Vissh

3

Phương thức bên trong sẽ ảnh hưởng đến phương thức bên ngoài nếu phương thức bên trong không được chú thích bằng @Transactional.

Trong trường hợp phương thức bên trong cũng được chú thích bằng @Transactional với REQUIRES_NEW, điều sau sẽ xảy ra.

...
@Autowired
private TestDAO testDAO;

@Autowired
private SomeBean someBean;

@Override
@Transactional(propagation=Propagation.REQUIRED)
public void outerMethod(User user) {
  testDAO.insertUser(user);
  try{
    someBean.innerMethod();
  } catch(RuntimeException e){
    // handle exception
  }
}


@Override
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void innerMethod() {
  throw new RuntimeException("Rollback this transaction!");
}

Phương thức bên trong được chú thích bằng REQUIRES_NEWvà ném một RuntimeException để nó sẽ thiết lập giao dịch của nó để khôi phục nhưng SẼ KHÔNG HIỆU ỨNG với giao dịch bên ngoài. Giao dịch bên ngoài bị DỪNG khi giao dịch bên trong bắt đầu và sau đó TIẾP TỤC SAU KHI giao dịch bên trong được kết thúc. Chúng chạy độc lập với nhau nên giao dịch bên ngoài CÓ THỂ cam kết thành công.


1
Để làm rõ cho người mới bắt đầu, tôi khá chắc rằng innerMethod () cần phải ở trên một bean khác (hay còn gọi là Đối tượng java được quản lý bằng Spring) so với NgoàiMethod (). Nếu cả hai đều nằm trên cùng một bean, tôi không nghĩ rằng innerMethod sẽ thực sự sử dụng hành vi Giao dịch được khai báo trong chú thích của nó. Thay vào đó, nó sẽ sử dụng những gì được khai báo trong khai báo externalMethod (). Điều này là do cách Spring xử lý AOP, được sử dụng cho các chú thích @Transactional ( docs.spring.io/spring/docs/3.0.x/spring-framework-reference/… )
johnsimer
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.