通過redis的腳本lua如何實現搶紅包功能_Redis

來源:腳本之家  責任編輯:小易  

1.完成所有工作,所有寫操作處理完成后腳本會自動退出。2.腳本運行時出錯并中途退出,所有以前執行的寫操作都已發生,但不會再有其他寫操作。3.Redis 通過 SHUTDOWN NOSAVE 關閉時(不保存)。4.你附加了調試器來“使”腳本完成#1 與#2(或其他手段來保證不會丟失數據)。對于使用數據庫開發軟件的人,我想你也認同只有情景#1 是最理想的。情景#2,#3,#4 都會導致數據異常(#2 與#4)和/或數據丟失(#3 和#4)。如果你很重視數據,你應該盡可能地阻止數據異常與丟失。這不是哲學,而是工作(This is not philosophy,this is doing your job)。但很遺憾目前的 Redis 也幫不了你多少。所以我決定改變這種情況www.anxorj.tw防采集請勿采集本網。

redis 腳本介紹

主要用途是:(1)描述界面:WOW和劍網三的界面都是用LUA寫的;(2)溝通引擎:游戲圖形引擎提供了一些接口庫,可以在LUA中調用;(3)服務器端:有些游戲,例如劍網三,在服務器端也會大量使用

Redis從2.6版本開始,通過內嵌支持Lua環境

除此之外Lua還可以使用redis.pcall函數實現對Redis的調用,redis.call和redis.pcall的不同在于,如果redis.call執行失敗,那么腳本執行結束會直接返回錯誤,而redis.pcall會忽略錯誤繼續執行腳本。

好處 減少網絡開銷?梢詫⒍鄠請求通過腳本的形式一次發送,減少網絡延遲 原子操作。redis將整個腳本當作一個整體去執行,中間不會被其他命令插入,無需擔心腳本執行過程中會出現競態條件 復用?蛻舳税l送的腳本會永久保存在redis中,可以復用這一腳本

主要用途是:(1)描述界面:WOW和劍網三的界面都是用LUA寫的;(2)溝通引擎:游戲圖形引擎提供了一些接口庫,可以在LUA中調用;(3)服務器端:有些游戲,例如劍網三,在服務器端也會大量使用LUA。

數據庫表設計

不存在現成的方法 如果要實現你說的功能 一般來說 還是按照正常的方法通過insert 或remove對表進行值的增減 然后再額外的對表進行一個監聽 當達到規定時間的時候,remove掉相關的值

簡單兩張表,一個紅包表,一個紅包領取記錄表

使用Redis的腳本功能實現Redis中數據簡單查詢,有需要的朋友可以參考下。在Redis的設計中,key是一切,對于Redis是可見的,而value對于Redis來說就是一個字節數組,Redis并不知道你的value中存儲

CREATE TABLE `t_red_envelope` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', `amount` decimal(10,2) DEFAULT NULL COMMENT '金額', `num` int(11) DEFAULT NULL COMMENT '數量(分割成幾分)', `create_time` datetime DEFAULT NULL COMMENT '創建時間', `update_time` datetime DEFAULT NULL COMMENT '更新時間', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COMMENT='紅包'CREATE TABLE `t_red_envelope_record` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', `user_id` bigint(20) DEFAULT NULL COMMENT '用戶id', `reward` decimal(10,2) DEFAULT NULL COMMENT '領取到獎勵', `red_envelope_id` bigint(20) DEFAULT NULL COMMENT '紅包id', `create_time` datetime DEFAULT NULL COMMENT '創建時間', `update_time` datetime DEFAULT NULL COMMENT '更新時間', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COMMENT='紅包領取記錄'

代碼編寫

首先,生成一個紅包,將其分成指定數量的隨機小紅包,以list結構(envelope:redEnvelopeId:紅包id作為key)存儲在reids中(以便搶紅包彈出數據)

public Long divideRedEnvelope(int amount, int num) { /** * 每個人至少分到一分錢,如果有2000分,6人,隨機得到五個小于1994(2000-6)的數 * 比如 a1=4,a2=120,a3=324,a4=500,a5=700(隨機拿到的五個數進行排序),那么紅包錢分別為: a1+1,a2-a1+1,a3-a2+1,a4-a3+1,a5-a4+1,1994-a5+1(總和剛好為2000) */ RedEnvelope redEnvelope = new RedEnvelope(); redEnvelope.setAmount(new BigDecimal(amount)); redEnvelope.setNum(num); redEnvelope.setCreateTime(new Date()); redEnvelope.setUpdateTime(new Date()); redEnvelopeDao.insert(redEnvelope); /** * 拿來隨機分的,按分來算 */ int totalAmount = amount * 100 - num; /** * 隨機數 */ int[] randomNum = new int[num - 1]; /** * 紅包金額 */ int[] redEnvelopeAmount = new int[num]; for (int i = 0; i < num - 1; i++) { int rand = new Random().nextInt(totalAmount); randomNum[i] = rand; } Arrays.sort(randomNum); /** * 條件語句分別分配的第一個、最后一個、中間的紅包 */ for (int i = 0; i < num; i++) { if (i == 0) { redEnvelopeAmount[i] = randomNum[i] + 1; } else if (i == num - 1) { redEnvelopeAmount[i] = totalAmount - randomNum[i - 1] + 1; } else { redEnvelopeAmount[i] = randomNum[i] - randomNum[i - 1] + 1; } } /** * 產生的小紅包key,以list存儲在reids中 */ String key = "envelope:redEnvelopeId:" + redEnvelope.getId(); Boolean flag = stringRedisTemplate.hasKey(key); if (!flag) { for (Integer i : redEnvelopeAmount) { stringRedisTemplate.opsForList().leftPush(key, i + ""); } } return redEnvelope.getId(); }

搶紅包時,根據用戶userId和紅包id,生成KEYS[1]、KEYS[2]、KEYS[3] (存儲小紅包的key、領取紅包記錄的key、用戶userId的key)傳入腳本中。

​     1、先判斷該用戶是否搶過紅包,有則返回-1,沒有則從紅包列表取出一個小紅包

​     2、步驟1的小紅包如果為空,則表明紅包已經沒搶光,返回 -2

​     3、否則返回取出的小紅包金額

public String grabRedEnvelope(Long userId, Long redEnvelopeId) { DefaultRedisScript<String> redisScript = new DefaultRedisScript<>(); redisScript.setResultType(String.class); redisScript.setScriptText(LuaScript.redLua); List<String> keyList = new ArrayList(); /** * 產生的小紅包key */ keyList.add("envelope:redEnvelopeId:" + redEnvelopeId); /** * 紅包領取記錄key */ keyList.add("envelope:record:" + redEnvelopeId); keyList.add("" + userId); keyList.add(String.valueOf(userId)); /** * -1 已經搶到紅包 -2 紅包已經完了 ,其余是搶到紅包并返回紅包余額 */ String result = stringRedisTemplate.execute(redisScript, keyList); return result; }

實現搶紅包的Lua腳本

public class LuaScript { /** * -1 已經搶到紅包 -2 紅包被搶光 re 紅包金額 ,keys[1]、keys[2]、keys[3]分別為存儲小紅包的key、紅包領取記錄key、用戶id */ public static String redLua = "if redis.call('hexists',KEYS[2],KEYS[3]) ~=0 then \n" + " return '-1';\n" + " else \n" + "local re=redis.call('rpop',KEYS[1]);\n" + "if re then\n" + "redis.call('hset',KEYS[2],KEYS[3],1);\n" + "return re;\n" + "else\n" + "return '-2';\n" + "end\n" + "end";}

測試

首先通過接口分配紅包生成一個100塊、份額為10份的紅包,并將其mysql數據庫和redis

通過jmeter進行壓測搶紅包

結果

github代碼鏈接

鏈接

總結

到此這篇關于通過redis的腳本lua如何實現搶紅包功能的文章就介紹到這了,更多相關redis的腳本lua實現搶紅包內容請搜索真格學網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持真格學網!

MySQL 與 Postgres在 1998-2003 年間,如果你想運行一個正規的數據庫驅動的網站/服務,但又沒有足夠的資金購買微軟或 Oracle 的數據庫,你可以選擇 MySQL 或 Postgres。很多人都選擇了 MySQL,因為它速度較快—主要是因為 MyISAM 存儲引擎沒有提供事務功能以此來換取性能7a686964616fe4b893e5b19e31333363363435,但速度確實很快。另一些人轉向 Postgres,因為雖然在相同硬件上其性能明顯低于 MySQL,但 Postgres 不會丟失數據(說實話,MySQL 數據丟失的情況非常少見,但丟了可不是鬧著玩的)。就這樣湊合著過了很久;MySQL 將其默認的存儲引擎從 MyISAM 過渡到了 InnoDB(其實很早就有了),這樣它的存儲引擎也得到了完整的事務支持和其他功能。與此同時,Postgres 也變快了,并添加了一個持續擴展的功能列表來使自己與眾不同,F在對于 MySQL 與 Postgres 的選擇只看個人的體驗與偏好,除了有時業務需要或領導決定使用其他選擇。數據完整性從很多方面來看,Redis 很像當初采用 InnoDB 前的 MySQL。而 Redis 采用了一種很合理的方式來保證數據完整性(復制,AOF 等),并且從 Redis2.6 開始引入的 Lua 腳本在功能與易用性方面為 Redis 的成長提供了很大助力。相對來說,Lua 腳本與其他數據庫中的存儲過程很相似,但腳本的執行有些許不同。在本文中最重要的一點就是一旦將腳本寫入數據庫,它會一直執行直到以下任一種情況出現:1.完成所有工作,所有寫操作處理完成后腳本會自動退出。2.腳本運行時出錯并中途退出,所有以前執行的寫操作都已發生,但不會再有其他寫操作。3.Redis 通過 SHUTDOWN NOSAVE 關閉時(不保存)。4.你附加了調試器來“使”腳本完成#1 與#2(或其他手段來保證不會丟失數據)。對于使用數據庫開發軟件的人,我想你也認同只有情景#1 是最理想的。情景#2,#3,#4 都會導致數據異常(#2 與#4)和/或數據丟失(#3 和#4)。如果你很重視數據,你應該盡可能地阻止數據異常與丟失。這不是哲學,而是工作(This is not philosophy,this is doing your job)。但很遺憾目前的 Redis 也幫不了你多少。所以我決定改變這種情況。實現 Lua 腳本事務我嘗試解決上面列表中的#2,#3,#4 問題,最終像下面這樣:腳本完成所有的工作,處理完寫操作后正常退出腳本執行過程中遇到錯誤退出,不更改任何數據(所有寫操作都回滾)無論有沒有寫入數據,都不會有數據丟失。這應該是所有的數據庫都希望做到的,我打算把這個加到 Redis 中,因為我們都希望 Redis有 這個功能。目前的 pull request 只是一個概念性的證明。也就是說,為了避免數據丟失,你要么 a)顯式使用事務的變體運行腳本,要么 b)強制所有 Lua 腳本調用帶配置選項的事務語義。還有很多的辦法使現在這個 patch 變得更好,我希望能得到 Salvatore(Redisw 作者)和其他社區的幫助內容來自www.anxorj.tw請勿采集。


  • 本文相關:
  • 詳解利用redis + lua解決搶紅包高并發的問題
  • 簡介lua腳本與redis數據庫的結合使用
  • redis執行lua腳本的好處與示例代碼
  • redis中如何使用lua腳本讓你的靈活性提高5個逼格詳解
  • 利用lua定制redis命令的方法詳解
  • redis如何使用lua腳本實例教程
  • nginx利用lua+redis實現動態封禁ip的方法
  • 詳解redis中lua腳本的應用和實踐
  • redis和lua使用過程中遇到的小問題
  • 利用yum安裝redis的方法詳解
  • phpredis提高消息隊列的實時性方法(推薦)
  • 詳解redis命令和鍵_動力節點java學院整理
  • 關于redis狀態監控和性能調優詳解
  • redis實現分布式的方法總結
  • redis配置文件代碼講解
  • redis實現信息已讀未讀狀態提示
  • redis源碼解析:集群手動故障轉移、從節點遷移詳解
  • ubuntu 16.04安裝redis的兩種方式教程詳解(apt和編譯方式)
  • redis中5種數據結構的使用場景介紹
  • 為什么在 Redis 實現 Lua 腳本事務
  • 為什么在 Redis 實現 Lua 腳本事務
  • redis加載lua腳本,怎么獲取數據
  • 為什么在 Redis 實現 Lua 腳本事務
  • redis lua腳本有什么用
  • redis 執行 xxx.luaxxx.lua 腳本如何傳參數。格式是什么
  • redis集群支持lua腳本嗎
  • 用lua 給redis 中塞值要怎么設置有效時間
  • redis 中有 4 億條記錄會占多少內存
  • Lua 中 變換數據類型。比如把數字變成string怎么寫?
  • 網站首頁網頁制作腳本下載服務器操作系統網站運營平面設計媒體動畫電腦基礎硬件教程網絡安全mssqlmysqlmariadboracledb2mssql2008mssql2005sqlitepostgresqlmongodbredisaccess數據庫文摘數據庫其它首頁redis詳解利用redis + lua解決搶紅包高并發的問題簡介lua腳本與redis數據庫的結合使用redis執行lua腳本的好處與示例代碼redis中如何使用lua腳本讓你的靈活性提高5個逼格詳解利用lua定制redis命令的方法詳解redis如何使用lua腳本實例教程nginx利用lua+redis實現動態封禁ip的方法詳解redis中lua腳本的應用和實踐redis和lua使用過程中遇到的小問題利用yum安裝redis的方法詳解phpredis提高消息隊列的實時性方法(推薦)詳解redis命令和鍵_動力節點java學院整理關于redis狀態監控和性能調優詳解redis實現分布式的方法總結redis配置文件代碼講解redis實現信息已讀未讀狀態提示redis源碼解析:集群手動故障轉移、從節點遷移詳解ubuntu 16.04安裝redis的兩種方式教程詳解(apt和編譯方式)redis中5種數據結構的使用場景介紹超強、超詳細redis數據庫入門教程redis常用命令、常見錯誤、配置技redis操作命令總結redis中5種數據結構的使用場景介64位windows下安裝redis教程redis中使用redis-dump導出、導入redis中統計各種數據大小的方法redis常用命令小結讓redis在你的系統中發揮更大作用centos 6.6下redis安裝配置記錄redis基本類型和使用方法詳解windows環境下redis+spring緩存實例講解windows環境部署redis集群redis 密碼設置和查看密碼的方法redis教程(一):redis簡介redis通過位圖法記錄在線用戶的狀態詳解redis教程(十二):服務器管理命令總結redis+mysql+quartz 一種紅包發送功能的實redislive監控redis服務的圖文教程_動力節解決redis開啟遠程訪問及密碼問題
    免責聲明 - 關于我們 - 聯系我們 - 廣告聯系 - 友情鏈接 - 幫助中心 - 頻道導航
    Copyright © 2017 www.anxorj.tw All Rights Reserved
    陕西快乐10分下载