Xem xét dịch vụ sau (giao dịch theo mặc định). Người chơi phải luôn có một tài khoản. Một trình phát không có ít nhất một tài khoản tương ứng là trạng thái lỗi.Grails 2.4.4: Cách khôi phục đáng tin cậy theo phương thức dịch vụ phức tạp
class playerService {
def createPlayer() {
Player p new Player(name: "Stephen King")
if (!p.save()) {
return [code: -1, errors:p.errors]
}
Account a = new Account(type: "cash")
if (!a.save()) {
// rollback p !
return [code: -2, errors:a.errors]
}
// commit only now!
return [code: 0, player:p]
}
}
Tôi đã thấy mô hình này bằng cách phát triển grails có kinh nghiệm, và khi tôi nói với họ rằng nếu tạo ra các tài khoản của người chơi thất bại vì lý do nào, nó sẽ không rollback các cầu thủ, và sẽ rời khỏi DB trong một không hợp lệ nhà nước, họ nhìn tôi như thể tôi đang phát điên vì những cây grails xử lý lăn ngược lại người chơi bởi vì các dịch vụ được giao dịch đúng không?
Vì vậy, sau đó, là một anh chàng SQL, tôi tìm cách gọi rollback trong grails. Không có một. Theo các bài đăng khác nhau, chỉ có 2 cách để buộc grails khôi phục trong một dịch vụ:
- ném một ngoại lệ không được chọn. Bạn biết điều này đúng không?
- không sử dụng phương pháp dịch vụ hoặc chú thích giao dịch, sử dụng cấu trúc này:
.
DomainObject.withTransaction {status ->
//stuff
if (someError) {
status.setRollbackOnly()
}
}
1. ném một ngoại lệ được kiểm soát
1,1 Vì vậy, chúng ta phải ném ngoại lệ thời gian chạy để rollback. Điều này là ok cho tôi (tôi thích trường hợp ngoại lệ), nhưng điều này sẽ không với các nhà phát triển grails chúng tôi có những người xem ngoại lệ như là một sự trở lại với Java và là uncool. Nó cũng có nghĩa là chúng ta phải thay đổi toàn bộ cách ứng dụng hiện đang sử dụng lớp dịch vụ của nó.
1.2 Nếu ngoại lệ được ném, bạn sẽ mất p.errors - bạn mất chi tiết xác thực.
1.3 Các nhà phát triển grails mới của chúng tôi không biết sự khác biệt giữa một ngoại lệ không được kiểm tra và kiểm tra, và không biết cách nói sự khác biệt. Điều này thực sự nguy hiểm.
1.4. sử dụng .save (failOnError: true) Tôi là một fan hâm mộ lớn của việc sử dụng này, nhưng nó không thích hợp ở khắp mọi nơi. Đôi khi bạn cần phải kiểm tra lý do trước khi đi xa hơn, không ném một ngoại lệ. Các ngoại lệ mà nó có thể tạo luôn được kiểm tra, luôn được bỏ chọn hay không? I E. sẽ failOnError AWLAYS rollback, bất kể nguyên nhân là gì? Không ai tôi đã hỏi biết câu trả lời cho điều này, điều này thật đáng lo ngại, họ đang sử dụng đức tin mù quáng để tránh các DB bị hỏng/không nhất quán.
1.5 Điều gì sẽ xảy ra nếu bộ điều khiển gọi dịch vụ A, gọi Dịch vụ B, sau đó là dịch vụ C. Dịch vụ A phải bắt giữ ngoại lệ và trả về giá trị trả về được định dạng độc đáo cho bộ điều khiển. Nếu Service C ném một ngoại lệ, được bắt bởi Service A, sẽ dịch vụ các giao dịch Bs được khôi phục? Điều này là rất quan trọng để biết để có thể xây dựng một ứng dụng làm việc.
CẬP NHẬT 1: Sau khi thực hiện một số kiểm tra, có vẻ như bất kỳ ngoại lệ thời gian chạy nào, ngay cả khi bị ném và bị bắt trong một số cuộc gọi con không liên quan, sẽ khiến mọi thứ trong phụ huynh quay trở lại. Tuy nhiên, không dễ để biết trong phiên cha mẹ rằng việc khôi phục này đã xảy ra - bạn cần đảm bảo rằng nếu bạn bắt bất kỳ ngoại lệ nào, bạn có thể trả lại hoặc chuyển một số thông báo lại cho người gọi để cho biết rằng nó đã bị lỗi một cách mà mọi thứ khác sẽ được khôi phục.
2.withTransaction
2.1 Đây có vẻ là một cấu trúc chợ. Làm cách nào để gọi điều này và tôi sẽ chuyển cho thông số "trạng thái" nào? "SetRollbackOnly" là gì chính xác là. Tại sao nó không chỉ được gọi là "rollback". Phần "Chỉ" là gì? Nó được gắn với một đối tượng miền, khi phương thức của bạn có thể muốn cập nhật một số đối tượng miền khác nhau.
2.2 Bạn phải đặt mã này ở đâu? Trong lớp DomainObject? Trong thư mục nguồn (tức là không có trong một dịch vụ hoặc bộ điều khiển?)? Trực tiếp trong bộ điều khiển? (chúng tôi không muốn sao chép logic nghiệp vụ trong bộ điều khiển)
3. Tình huống lý tưởng.
3,1 Các trường hợp chung là chúng tôi muốn tất cả mọi thứ chúng ta làm trong một phương pháp dịch vụ để quay trở lại nếu bất cứ điều gì ở chỗ phương pháp dịch vụ không thể được lưu lại cho lý do nào, hoặc ném bất kỳ ngoại lệ cho bất kỳ lý do (kiểm tra hoặc không được kiểm soát).
3.2 Lý tưởng nhất là tôi muốn các phương thức dịch vụ "luôn quay trở lại, trừ khi tôi gọi cam kết một cách rõ ràng", đây là chiến lược an toàn nhất, nhưng điều này là không thể.
Câu hỏi đặt ra là làm cách nào để đạt được tình huống lý tưởng?
Sẽ gọi lưu (failOnError: true) LUÔN khôi phục mọi thứ, bất kể lý do không thành công là gì? Điều này là không hoàn hảo, vì nó không phải là dễ dàng cho người gọi để biết được đối tượng miền tiết kiệm gây ra vấn đề.
Hoặc người ta có định nghĩa rất nhiều lớp ngoại lệ phân lớp runtimeException, sau đó khai thác rõ ràng từng bộ điều khiển trong bộ điều khiển để tạo phản hồi thích hợp không? Đây là cách Java cũ, và groovy của chúng tôi đã phát triển cách tiếp cận này do số lượng mã đĩa nồi hơi chúng ta sẽ phải viết.
Phương pháp nào mọi người sử dụng để đạt được điều này?
đây là một câu hỏi đối với tôi cũng vậy, tôi quyết định bắt tất cả mọi thứ trong điều khiển và ném lỗi của riêng tôi mà là con của RuntimeException. Tôi thấy đây là cách duy nhất để tạo ra phản ứng thích hợp. –