Có một số câu hỏi ở đây.
1) Tại sao chúng tôi không thể thực hiện gia tăng trong giao dịch mà không thể bị gián đoạn bởi lệnh khác?
Xin lưu ý rằng Redis "giao dịch" hoàn toàn khác so với hầu hết mọi người nghĩ rằng giao dịch nằm trong DBMS cổ điển.
# Does not work
redis.multi()
current = redis.get('powerlevel')
redis.set('powerlevel', current + 1)
redis.exec()
Bạn cần hiểu những gì được thực thi trên phía máy chủ (trong Redis) và những gì được thực thi trên phía máy khách (trong tập lệnh của bạn). Trong đoạn mã trên, các lệnh GET và SET sẽ được thực thi trên Redis side, nhưng việc gán cho current và tính toán hiện tại + 1 được cho là được thực thi ở phía máy khách.
Để đảm bảo nguyên tử, khối MULTI/EXEC trì hoãn việc thực thi lệnh Redis cho đến khi thực hiện. Vì vậy, khách hàng sẽ chỉ chồng lên các lệnh GET và SET trong bộ nhớ, và thực thi chúng trong một lần chụp và cuối cùng là nguyên tử. Tất nhiên, nỗ lực gán dòng điện vào kết quả của GET và tăng dần sẽ xảy ra trước đó. Trên thực tế, phương thức redis.get sẽ chỉ trả về chuỗi "QUEUED" để báo hiệu lệnh bị trì hoãn và việc tăng lên sẽ không hoạt động.
Trong khối MULTI/EXEC, bạn chỉ có thể sử dụng các lệnh có tham số có thể được biết đầy đủ trước khi bắt đầu khối. Bạn có thể muốn đọc the documentation để biết thêm thông tin.
2) Tại sao chúng ta cần lặp lại và chờ cho đến khi không ai thay đổi giá trị trước khi giao dịch bắt đầu?
Đây là ví dụ về mô hình lạc quan đồng thời.
Nếu chúng ta sử dụng không XEM/MULTI/EXEC, chúng ta sẽ có một điều kiện chủng tộc tiềm năng:
# Initial arbitrary value
powerlevel = 10
session A: GET powerlevel -> 10
session B: GET powerlevel -> 10
session A: current = 10 + 1
session B: current = 10 + 1
session A: SET powerlevel 11
session B: SET powerlevel 11
# In the end we have 11 instead of 12 -> wrong
Bây giờ chúng ta hãy thêm một chiếc đồng hồ/MULTI/EXEC khối. Với mệnh đề WATCH, các lệnh giữa MULTI và EXEC chỉ được thực thi nếu giá trị không thay đổi.
# Initial arbitrary value
powerlevel = 10
session A: WATCH powerlevel
session B: WATCH powerlevel
session A: GET powerlevel -> 10
session B: GET powerlevel -> 10
session A: current = 10 + 1
session B: current = 10 + 1
session A: MULTI
session B: MULTI
session A: SET powerlevel 11 -> QUEUED
session B: SET powerlevel 11 -> QUEUED
session A: EXEC -> success! powerlevel is now 11
session B: EXEC -> failure, because powerlevel has changed and was watched
# In the end, we have 11, and session B knows it has to attempt the transaction again
# Hopefully, it will work fine this time.
Vì vậy, bạn không phải lặp lại để đợi cho đến khi không ai thay đổi giá trị, cho đến khi Redis đảm bảo giá trị nhất quán và báo hiệu thành công.
Trong hầu hết các trường hợp, nếu "giao dịch" đủ nhanh và xác suất có ganh đua thấp, các bản cập nhật rất hiệu quả. Bây giờ, nếu có tranh chấp, một số hoạt động bổ sung sẽ phải được thực hiện đối với một số "giao dịch" (do lặp lại và thử lại). Nhưng dữ liệu sẽ luôn nhất quán và không cần khóa.
Bạn biết về trường hợp [incr] (http://redis.io/commands/incr) bị lỗi khi truy cập lại phải không? Nó thực hiện chính xác những gì bạn muốn trong ví dụ của bạn, mà không cần sử dụng một giao dịch. Tất nhiên đây không phải là câu trả lời cho chính câu hỏi đó, nhưng dù sao cũng đáng biết. – polvoazul
@polvoazul, tôi biết lệnh này, cảm ơn. Đó là một câu hỏi phổ biến không phải do trường hợp thực sự gây ra. – Marboni