2012-01-23 28 views
6

Trong ứng dụng Grails, hành vi mặc định của các phương thức dịch vụ là giao dịch và giao dịch được tự động khôi phục nếu một ngoại lệ không được kiểm tra được ném. Tuy nhiên, trong Groovy một không bắt buộc phải xử lý (hoặc rethrow) kiểm tra ngoại lệ, do đó, có một nguy cơ rằng nếu một phương pháp dịch vụ ném một ngoại lệ kiểm tra, giao dịch sẽ không được quay trở lại. Trên tài khoản này, có vẻ như nên chú thích mỗi lớp dịch vụ GrailsHành vi giao dịch dịch vụ Grails

@Transactional(rollbackFor = Throwable.class) 
class MyService { 

    void writeSomething() { 
    } 
} 

Giả sử tôi có các phương pháp khác trong MyService, một trong số đó chỉ đọc DB, còn người kia thì không chạm vào DB, như sau chú thích chính xác?

@Transactional(readOnly = true) 
void readSomething() {} 

// Maybe this should be propagation = Propagation.NOT_SUPPORTED instead? 
@Transactional(propagation = Propagation.SUPPORTS) 
void dontReadOrWrite() {} 

Để trả lời câu hỏi này, tôi đoán bạn sẽ cần phải biết những gì ý định của tôi là:

  • Nếu một ngoại lệ được ném từ phương pháp nào và có một giao dịch cơ bản dở dang, nó sẽ được cuộn lại. Ví dụ: nếu writeSomething() gọi dontReadOrWrite() và một ngoại lệ được ném từ thứ hai, giao dịch được khởi động trước đó sẽ được khôi phục. Tôi giả sử rằng thuộc tính cấp lớp rollbackFor được thừa hưởng bởi các phương thức riêng biệt trừ khi chúng ghi đè lên nó một cách rõ ràng.
  • Nếu không có giao dịch đang diễn ra, một giao dịch sẽ không được bắt đầu cho các phương thức như dontReadOrWrite
  • Nếu không có giao dịch nào được thực hiện, thì giao dịch chỉ đọc sẽ được bắt đầu. Nếu một giao dịch đọc-ghi đang được tiến hành, nó sẽ tham gia vào giao dịch này.

Trả lời

1

Tôi nghĩ rằng những gì bạn đang tìm kiếm là quản lý giao dịch chi tiết hơn và việc sử dụng chú thích @Transactional là đúng hướng cho điều đó. Điều đó nói rằng, có một Grails Transaction Handling Plugin có thể cung cấp cho bạn hành vi mà bạn đang tìm kiếm. Thông báo trước là bạn sẽ cần phải bọc các cuộc gọi phương thức dịch vụ của bạn trong một đóng cửa DomainClass.withTransaction và cung cấp hành vi không chuẩn mà bạn đang tìm kiếm như là một ánh xạ tham số cho phương thức withTransaction().

Như một lưu ý, trên chương trình phụ trợ, việc này đang thực hiện chính xác những gì bạn đang nói ở trên bằng cách sử dụng chú thích @Transactional để thay đổi hành vi của giao dịch khi chạy. Các tài liệu hướng dẫn plugin là tuyệt vời, vì vậy tôi không nghĩ rằng bạn sẽ tìm thấy chính mình mà không có hướng dẫn đầy đủ.

Hy vọng đây là những gì bạn đang tìm kiếm.

4

Mã của bạn là đúng như nó đi: bạn muốn sử dụng chú thích Spring @Transactional trên các phương thức riêng lẻ trong lớp dịch vụ của bạn để có được mức độ chi tiết bạn đang tìm kiếm, bạn đúng mà bạn muốn SUPPORTS cho dontReadOrWrite (NOT_SUPPORTED sẽ tạm dừng một giao dịch hiện tại, sẽ không mua cho bạn bất cứ thứ gì dựa trên những gì bạn đã mô tả và sẽ yêu cầu phần mềm của bạn sử dụng các chu kỳ, vì vậy bạn không thể nhận được), và bạn nói đúng là bạn muốn mặc định hành vi tuyên truyền (YÊU CẦU) cho readSomething. Một điều quan trọng cần lưu ý với hành vi giao dịch Spring là Spring thực hiện quản lý giao dịch bằng cách gói lớp của bạn trong một proxy để thiết lập giao dịch thích hợp, gọi phương thức của bạn và sau đó thực hiện giao dịch thích hợp khi kiểm soát trả về. Và (quan trọng), mã quản lý giao dịch này là chỉ được gọi khi bạn gọi phương thức trên proxy, điều này không xảy ra nếu writeSomething() gọi trực tiếp dontReadOrWrite() như trong dấu đầu dòng của bạn.

Nếu bạn cần hành vi giao dịch khác nhau trên một phương pháp đó được gọi là bằng một phương pháp khác, bạn đã có hai sự lựa chọn mà tôi biết nếu bạn muốn tiếp tục sử dụng các chú thích @Transactional Spring cho quản lý giao dịch:

  1. Move phương thức được gọi bởi phương thức khác vào một lớp dịch vụ khác, lớp này sẽ được truy cập từ lớp dịch vụ ban đầu của bạn thông qua Spring proxy.
  2. Rời khỏi phương thức của nó. Khai báo biến thành viên trong lớp dịch vụ của bạn có cùng kiểu với giao diện của lớp dịch vụ của bạn và làm cho nó @Autowired, nó sẽ cho bạn tham chiếu đến đối tượng Spring proxy của lớp dịch vụ của bạn. Sau đó, khi bạn muốn gọi phương thức của bạn với hành vi giao dịch khác nhau, hãy thực hiện nó trên biến thành viên đó thay vì trực tiếp và mã giao dịch Spring sẽ kích hoạt như bạn muốn.

Phương pháp tiếp cận # 1 là tuyệt vời nếu hai phương pháp này thực sự không liên quan, bởi vì nó giải quyết được vấn đề của bạn mà không gây nhầm lẫn với bất kỳ ai kết thúc việc duy trì mã của bạn và không có cách nào vô tình quên gọi phương thức đã bật giao dịch .

Phương pháp tiếp cận # 2 thường là tùy chọn tốt hơn, giả sử rằng các phương pháp của bạn đều nằm trong cùng một dịch vụ vì lý do và bạn sẽ không thực sự muốn tách chúng ra. Nhưng nó gây nhầm lẫn cho một người duy trì không hiểu nếp nhăn của các giao dịch mùa xuân này, và bạn phải nhớ gọi nó theo cách đó ở mỗi nơi bạn gọi nó, vì vậy có một mức giá cho nó. Tôi thường sẵn sàng trả giá đó để không làm hỏng các lớp dịch vụ của tôi một cách không tự nhiên, nhưng như thường lệ, nó sẽ tùy thuộc vào tình huống của bạn.