2009-06-23 30 views
7

Tôi đang tạo một ứng dụng web Django cho phép người dùng tạo một tập hợp các thay đổi qua một loạt các GET/POST trước khi cam kết chúng vào cơ sở dữ liệu (hoặc hoàn nguyên) với POST cuối cùng . Tôi phải giữ các bản cập nhật được phân lập từ bất kỳ người dùng cơ sở dữ liệu đồng thời cho đến khi họ được xác nhận (đây là một cấu hình front-end), quyết định cam kết sau mỗi POST.Giao dịch mỗi phiên trong Django

Giải pháp ưa thích của tôi là sử dụng giao dịch mỗi phiên. Điều này giữ tất cả các vấn đề của việc ghi nhớ những gì đã thay đổi (và cách nó ảnh hưởng đến các truy vấn tiếp theo), cùng với việc thực hiện cam kết/rollback, trong cơ sở dữ liệu mà nó thuộc về. Khóa bế tắc và khóa kéo dài không phải là một vấn đề, do các ràng buộc bên ngoài chỉ có thể có một người dùng định cấu hình hệ thống tại một thời điểm bất kỳ và chúng hoạt động tốt.

Tuy nhiên, tôi không thể tìm thấy tài liệu về thiết lập ORM của Django để sử dụng loại mô hình giao dịch này. Tôi đã ném cùng một miếng vá khỉ tối thiểu (ew!) Để giải quyết vấn đề, nhưng không thích giải pháp mong manh như vậy. Có ai khác đã làm điều này trước đây không? Tôi đã bỏ lỡ một số tài liệu ở đâu đó?

(phiên bản Mỹ của Django là 1.0.2 cuối cùng, và tôi đang sử dụng một cơ sở dữ liệu Oracle.)

Trả lời

9

Nhiều, đồng thời, giao dịch phiên quy mô nói chung sẽ dẫn đến bế tắc hoặc tồi tệ hơn (tồi tệ hơn == livelock, dài sự chậm trễ trong khi khóa được tổ chức bởi một phiên khác.)

Thiết kế này không phải là chính sách tốt nhất, đó là lý do tại sao Django không khuyến khích nó.

Giải pháp tốt hơn là như sau.

  1. Memento lớp ghi lại thay đổi của người dùng. Đây có thể là bản sao đã lưu của thông tin nhập biểu mẫu của họ. Bạn có thể cần phải ghi lại thông tin bổ sung nếu các thay đổi trạng thái rất phức tạp. Nếu không, một bản sao của biểu mẫu đầu vào có thể là đủ.

  2. Tích lũy chuỗi các đối tượng Memento trong phiên của họ. Lưu ý rằng mỗi bước trong giao dịch sẽ liên quan đến việc tìm nạp dữ liệu và xác thực để xem liệu chuỗi các vật lưu niệm sẽ vẫn "hoạt động" hay không. Đôi khi họ sẽ không làm việc bởi vì ai đó đã thay đổi một cái gì đó trong chuỗi vật lưu niệm này. Gì bây giờ?

  3. Khi bạn trình bày 'sẵn sàng cam kết?' , bạn đã phát lại chuỗi Vật lưu niệm và chắc chắn chúng sẽ hoạt động. Khi gửi "Cam kết", bạn phải phát lại Mementos lần cuối cùng, hy vọng họ vẫn sẽ hoạt động. Nếu họ làm, tuyệt vời. Nếu không, ai đó đã thay đổi thứ gì đó và bạn quay lại bước 2: bây giờ là gì?

Điều này có vẻ phức tạp.

Vâng, đúng vậy. Tuy nhiên nó không giữ bất kỳ ổ khóa nào, cho phép tốc độ phồng rộp và ít cơ hội cho bế tắc. Giao dịch được giới hạn trong chức năng xem "Cam kết" thực sự áp dụng chuỗi Mementos vào cơ sở dữ liệu, lưu kết quả và thực hiện cam kết cuối cùng để kết thúc giao dịch.

Thay thế - giữ khóa trong khi người dùng bước ra cho một tách cà phê nhanh trên bước n-1 trên n - không hoạt động.

Để biết thêm thông tin về Memento, hãy xem this.

+0

Deadlock và người dùng bước ra cho cà phê không phải là một vấn đề (sẽ có một bộ điều khiển, và bằng cách thiết kế toàn bộ cập nhật được thực hiện dưới một khóa). Đúng nếu tôi sai, nhưng các vật lưu niệm sẽ không thực sự làm việc với ORM, đúng không? –

+0

Vật lưu niệm - làm mẫu thiết kế - hoạt động với mọi thứ. Giao dịch dài hạn, nhiều bước với các khóa tích lũy chậm sẽ dẫn đến bế tắc. Cách duy nhất để tránh bế tắc là có một người dùng. –

+0

ORM của Django cung cấp ánh xạ tự động từ các bảng đến biểu mẫu và ngược lại. Tôi có thể móc điều này lên mẫu Memento không, hoặc tôi có cần ngừng sử dụng tính năng này không? –

1

Trong trường hợp bất kỳ ai khác có cùng một vấn đề giống như tôi (tôi hy vọng là không), đây là khỉ của tôi. Đó là mong manh và xấu xí, và thay đổi phương pháp riêng tư, nhưng may mắn là nó nhỏ. Xin vui lòng không sử dụng nó trừ khi bạn thực sự phải. Như đã đề cập bởi những người khác, bất kỳ ứng dụng sử dụng nó có hiệu quả ngăn cản nhiều người dùng thực hiện cập nhật cùng một lúc, trên hình phạt của bế tắc. (Trong ứng dụng của tôi, có thể có nhiều độc giả, nhưng nhiều bản cập nhật đồng thời được loại trừ một cách có chủ ý.)

Tôi có đối tượng "người dùng" tồn tại trong phiên người dùng và chứa đối tượng kết nối liên tục. Khi tôi xác nhận một tương tác HTTP cụ thể là một phần của một phiên, tôi cũng lưu trữ đối tượng người dùng trên django.db.connection, đó là luồng-cục bộ.

def monkeyPatchDjangoDBConnection(): 
    import django.db 
    def validConnection(): 
     if django.db.connection.connection is None: 
      django.db.connection.connection = django.db.connection.user.connection 
     return True 
    def close(): 
     django.db.connection.connection = None 
    django.db.connection._valid_connection = validConnection 
    django.db.connection.close = close 
monkeyPatchDBConnection() 

def setUserOnThisThread(user): 
    import django.db 
    django.db.connection.user = user 

Điều cuối cùng được gọi tự động khi bắt đầu bất kỳ phương thức nào được chú thích với @login_required, vì vậy 99% mã của tôi được cách ly với các chi tiết cụ thể của bản hack này.

2

Tôi đã đưa ra một cái gì đó tương tự như mô hình Memento, nhưng đủ khác nhau mà tôi nghĩ rằng nó mang bài. Khi người dùng bắt đầu phiên chỉnh sửa, tôi sao chép đối tượng đích vào một đối tượng tạm thời trong cơ sở dữ liệu. Tất cả các thao tác chỉnh sửa tiếp theo đều ảnh hưởng đến bản sao. Thay vì lưu trạng thái đối tượng trong memento ở mỗi thay đổi, tôi lưu trữ các hoạt động hoạt động đối tượng. Khi tôi áp dụng một hoạt động cho một đối tượng, nó trả về hoạt động nghịch đảo mà tôi lưu trữ.

Tiết kiệm hoạt động rẻ hơn nhiều so với vật lưu niệm, vì các thao tác có thể được mô tả với một vài mục dữ liệu nhỏ, trong khi đối tượng đang được chỉnh sửa lớn hơn nhiều. Ngoài ra tôi áp dụng các hoạt động khi tôi đi và lưu các bản hoàn tác, để tạm thời trong db luôn tương ứng với phiên bản trong trình duyệt của người dùng. Tôi không bao giờ phải phát lại một tập hợp các thay đổi; tạm thời luôn luôn chỉ là một hoạt động ra khỏi phiên bản tiếp theo.

Để thực hiện "hoàn tác", tôi bật đối tượng hoàn tác cuối cùng khỏi ngăn xếp (vì nó là - bằng cách truy xuất hoạt động mới nhất cho đối tượng tạm thời từ db) áp dụng nó cho tạm thời và trả về tạm thời được chuyển đổi. Tôi cũng có thể đẩy các hoạt động kết quả vào một redo stack nếu tôi quan tâm để thực hiện làm lại.

Để triển khai "lưu thay đổi", nghĩa là cam kết, tôi hủy kích hoạt và đóng dấu thời gian đối tượng gốc và kích hoạt tạm thời tại vị trí của đối tượng gốc.

Để triển khai "hủy", nghĩa là khôi phục, tôi không làm gì cả! Tôi có thể xóa tạm thời, tất nhiên, bởi vì không có cách nào để người dùng truy xuất nó sau khi phiên chỉnh sửa kết thúc, nhưng tôi muốn giữ các phiên chỉnh sửa bị hủy để tôi có thể chạy thống kê trên chúng trước khi xóa chúng bằng công việc cron .

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