2012-07-02 27 views
7

Tôi đang gói gọn một tập hợp các lệnh Redis phức tạp trong một giao dịch MULTI, nhưng logic trong giao dịch phụ thuộc vào các giá trị đã có trong Redis. Nhưng tất cả đọc trong một giao dịch dường như trở nilLàm thế nào tôi có thể đọc từ Redis bên trong khối MULTI trong Ruby?

Dưới đây là một ví dụ mà chứng tỏ vấn đề:

[Dev]> $redis.set("foo", "bar") 
=> "OK" 
[Dev]> $redis.multi{ $redis.set("foo", "baz") if $redis.get("foo") == "bar" } 
=> ["bar"] 
[Dev]> $redis.get("foo") 
=> "bar" 

Rõ ràng là tôi muốn các giá trị trả về cuối cùng là 'baz' - làm thế nào tôi có thể đạt được điều này?

+0

Tôi e rằng bạn không thể làm điều đó. –

Trả lời

1

Như Sergio nêu trong nhận xét của mình, bạn không thể tùy chọn thực thi khối MULTI như vậy trong Redis. Xem documentation on transactions:

Cả hai lệnh hoặc không được xử lý.

Bạn có thể, tuy nhiên, sử dụng WATCH để thực hiện khóa lạc bằng check-và-set (pseudo code):

SET foo bar 
WATCH foo 
$foo = GET foo 
MULTI 
if $foo == 'bar' 
    SET foo baz 
EXEC 
GET foo 

Sử dụng WATCH, giao dịch sẽ chỉ được thực hiện nếu phím xem (s) chưa được thay đổi. Nếu phím đồng hồ bị thay đổi, EXEC sẽ không thành công và bạn có thể thử lại.

Một khả năng khác là sử dụng chức năng tập lệnh, nhưng điều đó chỉ khả dụng trong phiên bản 2.6.

16

Bạn không thể, vì tất cả các lệnh (bao gồm cả get) đều thực sự được thực thi tại thời gian thực hiện. Trong tình huống này, lệnh get chỉ trả về một đối tượng tương lai, không phải giá trị thực.

Có hai cách để thực hiện giao dịch đó.

Sử dụng một điều khoản XEM

Mệnh đồng hồ được sử dụng để bảo vệ chống lại các cập nhật đồng thời. Nếu giá trị của biến được cập nhật giữa điều khoản đồng hồ và đa, thì các lệnh trong khối đa không được áp dụng. Tùy thuộc vào khách hàng để thử giao dịch lần khác.

loop do 
    $redis.watch "foo" 
    val = $redis.get("foo") 
    if val == "bar" then 
     res = $redis.multi do |r| 
      r.set("foo", "baz") 
     end 
     break if res 
    else 
     $redis.unwatch "foo" 
     break 
    end 
end 

Tại đây, tập lệnh hơi phức tạp vì nội dung của khối có thể trống, vì vậy không có cách nào dễ dàng để biết giao dịch có bị hủy hay không. Nó thường dễ dàng hơn khi khối đa trả về kết quả trong mọi trường hợp ngoại trừ nếu giao dịch bị hủy.

Sử dụng Lua server-side scripting

Với Redis 2.6 hoặc tốt hơn, kịch bản Lua thể được thực hiện trên máy chủ. Việc thực hiện toàn bộ kịch bản là nguyên tử. Nó có thể dễ dàng được triển khai trong Ruby:

cmd = <<EOF 
    if redis.call('get',KEYS[1]) == ARGV[1] then 
     redis.call('set',KEYS[1],ARGV[2]) 
    end 
EOF 
$redis.eval cmd, 1, "foo", "bar", "baz" 

Điều này thường đơn giản hơn nhiều so với sử dụng mệnh đề WATCH.

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