您好,登錄后才能下訂單哦!
本篇內容主要講解“redis樂觀鎖與悲觀鎖怎么使用”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“redis樂觀鎖與悲觀鎖怎么使用”吧!
Redis是一個內存中的鍵值存儲系統,支持多種數據結構,如字符串、哈希、列表等。Redis提供了兩種鎖機制,即樂觀鎖和悲觀鎖。
樂觀鎖是一種樂觀的并發控制策略,它認為數據在大多數情況下不會被其他線程占用,因此每次需要修改數據時,都不會獲取鎖,而是直接進行修改。在Redis中,可以通過WATCH和CAS命令來實現樂觀鎖,WATCH命令用于監視一個或多個鍵,CAS命令用于檢查并更新鍵的值。
例如,假設有一個計數器鍵counter,多個客戶端都需要對其進行操作。使用樂觀鎖的方式,可以在每個客戶端執行操作之前,先通過WATCH命令監視counter鍵:
WATCH counter current_count = GET counter new_count = current_count + 1 MULTI SET counter new_count EXEC
然后,在EXEC命令執行之前,使用GET命令再次獲取counter鍵的值,并將其與之前獲取的值進行比較。如果值相等,就說明期間沒有其他客戶端對counter鍵進行了修改,此時可以使用CAS命令將新值設置到counter鍵中。如果值不相等,則說明期間有其他客戶端對counter鍵進行了修改,需要重新執行操作。
GET counter
悲觀鎖是一種悲觀的并發控制策略,它認為數據在大多數情況下都會被其他線程占用,因此每次需要修改數據時,都會先獲取鎖,確保在修改期間沒有其他線程可以訪問該數據。在Redis中,可以通過WATCH命令來實現悲觀鎖,該命令可以監視一個或多個鍵,如果在事務執行期間有任何被監視鍵的值發生了變化,整個事務會被回滾。
還是上文的例子
WATCH counter current_count = GET counter new_count = current_count + 1 MULTI SET counter new_count EXEC
如果在執行事務期間,有其他客戶端修改了counter鍵,那么整個事務會被回滾,需要重新執行。
悲觀鎖的優點在于它可以確保數據的一致性,但缺點在于它需要獲取鎖,可能會引起線程的阻塞,影響并發性能。
假設有一個電商平臺,用戶可以在平臺上購買商品。為了保證數據的一致性,我們可以使用Redis的樂觀鎖來實現商品庫存的扣減。
首先,我們需要在Redis中保存每個商品的庫存信息,使用hash數據結構來保存,例如:
然后,在業務邏輯中,當用戶購買一個商品時,需要執行以下步驟:
使用WATCH命令監視商品庫存鍵,例如stock:sku001;
使用GET命令獲取當前商品庫存數量;
檢查商品庫存是否足夠,如果不足,直接返回錯誤信息;
計算新的庫存數量,并使用MULTI命令開啟一個事務;
使用HSET命令將新的庫存數量保存到Redis中;
執行事務,如果在執行期間有其他客戶端修改了商品庫存,會回滾事務,需要重新執行。
下面是使用Spring Boot實現的示例代碼:
@Service public class OrderService { private final RedisTemplate<String, Integer> redisTemplate; @Autowired public OrderService(RedisTemplate<String, Integer> redisTemplate) { this.redisTemplate = redisTemplate; } public void placeOrder(String sku, int quantity) { String stockKey = "stock:" + sku; while (true) { // 監視商品庫存鍵,以便在事務開始前檢測是否有其他客戶端修改了庫存 redisTemplate.watch(stockKey); // 獲取當前庫存數量 int currentStock = redisTemplate.opsForHash().get(stockKey, sku); // 檢查庫存是否足夠 if (currentStock < quantity) { // 庫存不足,放棄事務并拋出異常 redisTemplate.unwatch(); throw new RuntimeException("Out of stock"); } // 計算新的庫存數量 int newStock = currentStock - quantity; // 開始事務 redisTemplate.multi(); // 更新庫存數量 redisTemplate.opsForHash().put(stockKey, sku, newStock); // 提交事務 List<Object> results = redisTemplate.exec(); // 如果事務執行成功,則退出循環 if (results != null) { break; } // 如果事務執行失敗,則重試 } } }
在上面的代碼中,我們使用RedisTemplate來操作Redis,其中watch方法用于監視商品庫存鍵,opsForHash方法用于獲取和修改商品庫存的值,multi和exec方法用于開啟和提交事務。
除了樂觀鎖,Redis還支持悲觀鎖,可以通過設置NX(Not Exist)或XX(Exist)標志來實現。例如,當NX標志設置為true時,如果鎖不存在,會返回OK,并創建一個鎖;如果鎖已經存在,會返回null,表示獲取鎖失敗。反之,當XX標志設置為true時,如果鎖已經存在,會返回OK,表示獲取鎖成功;如果鎖不存在,會返回null,表示獲取鎖失敗。
下面是使用Spring Boot實現的悲觀鎖示例代碼:
@Service public class OrderService { private final RedisTemplate<String, String> redisTemplate; @Autowired public OrderService(RedisTemplate<String, String> redisTemplate) { this.redisTemplate = redisTemplate; } public void placeOrder(String sku, int quantity) { String lockKey = "lock:" + sku; // 嘗試獲取鎖,如果鎖已經存在,說明有其他線程正在執行相關操作 Boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "locked"); if (!locked) { // 獲取鎖失敗,拋出異常 throw new RuntimeException("Unable to acquire lock"); } // 設置鎖的過期時間,防止鎖被一直占用 redisTemplate.expire(lockKey, 10, TimeUnit.SECONDS); try { // 執行訂單創建、扣減庫存等操作 } finally { // 釋放鎖 redisTemplate.delete(lockKey); } } }
在上面的代碼中,我們使用setIfAbsent方法來嘗試獲取鎖,如果鎖已經存在,說明其他線程正在執行相關操作,此時會返回false,表示獲取鎖失敗;否則,會返回true,表示獲取鎖成功。如果獲取鎖成功,我們會設置鎖的過期時間,并執行相關操作,最后釋放鎖。
到此,相信大家對“redis樂觀鎖與悲觀鎖怎么使用”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。