springboot中redis操作Hash踩坑解決
問題
如下代碼是獲取短信驗證碼功能,會先檢查下前面五分鐘內(nèi)發(fā)沒發(fā)過驗證碼,也就是有沒有手機號對應(yīng)緩存key,有的話刷新過期時間,沒有就緩存一下設(shè)置過期時間為5分鐘。
但是經(jīng)過測試在第一次發(fā)送時緩存的key沒有設(shè)置過期時間,也就是說永不過期,當再發(fā)送一次后過期時間就正常刷新為5分鐘了。
@Override public void getSmsCaptcha(String phone) { String hashKey = "login:sms:captcha:" + phone; BoundHashOperations<String, String, String> hashOps = stringRedisTemplate.boundHashOps(hashKey); // 初始檢查 String lastSendTimestamp = hashOps.get("lastSendTimestamp"); String sendCount = hashOps.get("sendCount"); String captcha = hashOps.get("captcha"); hashOps.expire(5, TimeUnit.MINUTES); // 設(shè)置過期時間為5分鐘 // 判斷發(fā)送次數(shù)是否超過限制 if (StringUtils.isNotBlank(sendCount) && Integer.parseInt(sendCount) >= 5) { hashOps.expire(24, TimeUnit.HOURS); // 重新設(shè)置過期時間為24H throw new GeneralBusinessException("發(fā)送次數(shù)過多,請24H后再試"); } // 判斷發(fā)送頻率是否過高 if (StringUtils.isNotBlank(lastSendTimestamp)) { long lastSendTime = Long.parseLong(lastSendTimestamp); long currentTime = System.currentTimeMillis(); long elapsedTime = currentTime - lastSendTime; long interval = 60 * 1000; // 60秒 if (elapsedTime < interval) { throw new GeneralBusinessException("發(fā)送短信過于頻繁,請稍后再試"); } } // 更新發(fā)送次數(shù) int newSendCount = StringUtils.isNotBlank(sendCount) ? Integer.parseInt(sendCount) + 1 : 1; // 生成新驗證碼 if (StringUtils.isBlank(captcha)) { captcha = RandomStringUtils.randomNumeric(6); } // 發(fā)送短信 if (!smsUtil.sendSms(phone, captcha)) { throw new GeneralBusinessException("發(fā)送短信失敗"); } // 更新 Redis 中的信息 hashOps.put("captcha", captcha); hashOps.put("lastSendTimestamp", String.valueOf(System.currentTimeMillis())); hashOps.put("sendCount", String.valueOf(newSendCount)); }
原因
BoundHashOperations<String, String, String> hashOps = stringRedisTemplate.boundHashOps(hashKey);
使用 boundHashOps 方法時指定的 hashKey 在 Redis 中不存在,那么 boundHashOps 將返回一個空的 BoundHashOperations 對象。這個對象仍然是可用的,但不包含任何數(shù)據(jù)。當?shù)谝淮伟l(fā)送時,上面代碼會先獲取這個key,并設(shè)置過期時間為5分鐘,但其實這個key不存在導致設(shè)置過期時間失敗但是沒有任何報錯,當?shù)诙伟l(fā)送時,檢查到這個key存在了,過期時間就設(shè)置成功了。
解決方案
把刷新緩存時間操作放在put數(shù)據(jù)之后,這樣保證了這個key存在后再設(shè)置過期時間。
@Override public void getSmsCaptcha(String phone) { String hashKey = "login:sms:captcha:" + phone; BoundHashOperations<String, String, String> hashOps = stringRedisTemplate.boundHashOps(hashKey); // 初始檢查 String lastSendTimestamp = hashOps.get("lastSendTimestamp"); String sendCount = hashOps.get("sendCount"); String captcha = hashOps.get("captcha"); //。。。。。。。。。。。。。。。。。。。。。。。 // 更新 Redis 中的信息 hashOps.put("captcha", captcha); hashOps.put("lastSendTimestamp", String.valueOf(System.currentTimeMillis())); hashOps.put("sendCount", String.valueOf(newSendCount)); //設(shè)置數(shù)據(jù)后再設(shè)置過期時間 hashOps.expire(5, TimeUnit.MINUTES); // 設(shè)置過期時間為5分鐘 }
到此這篇關(guān)于spring boot中redis操作Hash踩坑解決的文章就介紹到這了,更多相關(guān)springboot redis操作Hash內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java定時任務(wù)ScheduledThreadPoolExecutor示例詳解
這篇文章主要介紹了Java定時任務(wù)ScheduledThreadPoolExecutor示例詳解,這里使用scheduleAtFixedRate方法安排一個任務(wù),該任務(wù)是一個 Runnable 匿名類,其run方法中調(diào)用了new LoginViewTimeTask().loginStatisticsHandle()方法,需要的朋友可以參考下2023-11-11Mybatis操作多數(shù)據(jù)源的實現(xiàn)
本文主要介紹了Mybatis操作多數(shù)據(jù)源,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-05-05Java線程中synchronized和volatile關(guān)鍵字的區(qū)別詳解
這篇文章主要介紹了Java線程中synchronized和volatile關(guān)鍵字的區(qū)別詳解,synchronzied既能夠保障可見性,又能保證原子性,而volatile只能保證可見性,無法保證原子性,volatile不需要加鎖,比synchronized更輕量級,不會阻塞線程,需要的朋友可以參考下2024-01-01SpringBoot數(shù)據(jù)層測試事務(wù)回滾的實現(xiàn)流程
這篇文章主要介紹了SpringBoot數(shù)據(jù)層測試事務(wù)回滾的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習吧2022-10-10Java 模擬數(shù)據(jù)庫連接池的實現(xiàn)代碼
這篇文章主要介紹了Java 模擬數(shù)據(jù)庫連接池的實現(xiàn),本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-02-02