日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

Spring Boot實現數據訪問計數器方案詳解

瀏覽:23日期:2023-06-26 18:28:45
目錄1、數據訪問計數器2、代碼實現2.1、方案說明2.2、代碼2.3、調用1、數據訪問計數器

  在Spring Boot項目中,有時需要數據訪問計數器。大致有下列三種情形:

1)純計數:如登錄的密碼錯誤計數,超過門限N次,則表示計數器滿,此時可進行下一步處理,如鎖定該賬戶。

2)時間滑動窗口:設窗口寬度為T,如果窗口中尾幀時間與首幀時間差大于T,則表示計數器滿。

  例如使用redis緩存時,使用key查詢redis中數據,如果有此key數據,則返回對象數據;如無此key數據,則查詢數據庫,但如果一直都無此key數據,從而反復查詢數據庫,顯然有問題。此時,可使用時間滑動窗口,對于查詢的失敗的key,距離首幀T時間(如1分鐘)內,不再查詢數據庫,而是直接返回無此數據,直到新查詢的時間超過T,更新滑窗首幀為新時間,并執行一次查詢數據庫操作。

3)時間滑動窗口+計數:這往往在需要進行限流處理的場景使用。如T時間(如1分鐘)內,相同key的訪問次數超過超過門限N,則表示計數器滿,此時進行限流處理。

2、代碼實現2.1、方案說明

1)使用字典來管理不同的key,因為不同的key需要單獨計數。

2)上述三種情況,使用類型屬性區分,并在構造函數中進行設置。

3)滑動窗口使用雙向隊列Deque來實現。

4)考慮到訪問并發性,讀取或更新時,加鎖保護。

2.2、代碼

package com.abc.example.service;import java.util.ArrayDeque;import java.util.Deque;import java.util.HashMap;import java.util.Map;/** * @className: DacService * @description: 數據訪問計數服務類 * @summary: * @history: * ------------------------------------------------------------------------------ * dateversionmodifierremarks * ------------------------------------------------------------------------------ * 2021/08/031.0.0sheng.zheng初版 * */public class DacService {// 計數器類型:1-數量;2-時間窗口;3-時間窗口+數量private int counterType; // 計數器數量門限private int counterThreshold = 5;// 時間窗口長度,單位毫秒private int windowSize = 60000;// 對象key的訪問計數器private Map<String,Integer> itemMap;// 對象key的訪問滑動窗口private Map<String,Deque<Long>> itemSlideWindowMap;/** * 構造函數 * @param counterType: 計數器類型,值為1,2,3之一 * @param counterThreshold: 計數器數量門限,如果類型為1或3,需要此值 * @param windowSize: 窗口時間長度,如果為類型為2,3,需要此值 */public DacService(int counterType, int counterThreshold, int windowSize) {this.counterType = counterType;this.counterThreshold = counterThreshold;this.windowSize = windowSize;if (counterType == 1) { // 如果與計數器有關 itemMap = new HashMap<String,Integer>();}else if (counterType == 2 || counterType == 3) { // 如果與滑動窗口有關 itemSlideWindowMap = new HashMap<String,Deque<Long>>();}}/** * * @methodName: isItemKeyFull * @description: 對象key的計數是否將滿 * @param itemKey: 對象key * @param timeMillis : 時間戳,毫秒數,如為滑窗類計數器,使用此參數值 * @return: 滿返回true,否則返回false * @history: * ------------------------------------------------------------------------------ * dateversionmodifierremarks * ------------------------------------------------------------------------------ * 2021/08/031.0.0sheng.zheng初版 * 2021/08/081.0.1sheng.zheng支持多種類型計數器 * */public boolean isItemKeyFull(String itemKey,Long timeMillis) {boolean bRet = false;if (this.counterType == 1) { // 如果為計數器類型 if (itemMap.containsKey(itemKey)) {synchronized(itemMap) { Integer value = itemMap.get(itemKey); // 如果計數器將超越門限 if (value >= this.counterThreshold - 1) {bRet = true; }} }else {// 新的對象key,視業務需要,取值true或falsebRet = true; }}else if(this.counterType == 2){ // 如果為滑窗類型 if (itemSlideWindowMap.containsKey(itemKey)) { Deque<Long> itemQueue = itemSlideWindowMap.get(itemKey); synchronized(itemQueue) { if (itemQueue.size() > 0) { Long head = itemQueue.getFirst(); if (timeMillis - head >= this.windowSize) { // 如果窗口將滿 bRet = true; } } } }else {// 新的對象key,視業務需要,取值true或falsebRet = true; }}else if(this.counterType == 3){ // 如果為滑窗+數量類型 if (itemSlideWindowMap.containsKey(itemKey)) {Deque<Long> itemQueue = itemSlideWindowMap.get(itemKey);synchronized(itemQueue) { Long head = 0L; // 循環處理頭部數據,確保新數據幀加入后,維持窗口寬度 while(true) { // 取得頭部數據 head = itemQueue.peekFirst(); if (head == null || timeMillis - head <= this.windowSize) { break;}// 移除頭部itemQueue.remove(); } if (itemQueue.size() >= this.counterThreshold -1) {// 如果窗口數量將滿bRet = true; }} }else {// 新的對象key,視業務需要,取值true或falsebRet = true; }}return bRet;}/** * * @methodName: resetItemKey * @description: 復位對象key的計數 * @param itemKey: 對象key * @history: * ------------------------------------------------------------------------------ * dateversionmodifierremarks * ------------------------------------------------------------------------------ * 2021/08/031.0.0sheng.zheng初版 * 2021/08/081.0.1sheng.zheng支持多種類型計數器 * */public void resetItemKey(String itemKey) {if (this.counterType == 1) { // 如果為計數器類型 if (itemMap.containsKey(itemKey)) {// 更新值,加鎖保護synchronized(itemMap) { itemMap.put(itemKey, 0);} }}else if(this.counterType == 2){ // 如果為滑窗類型 // 清空 if (itemSlideWindowMap.containsKey(itemKey)) {Deque<Long> itemQueue = itemSlideWindowMap.get(itemKey);if (itemQueue.size() > 0) { // 加鎖保護 synchronized(itemQueue) { // 清空 itemQueue.clear(); }} }}else if(this.counterType == 3){ // 如果為滑窗+數量類型 if (itemSlideWindowMap.containsKey(itemKey)) {Deque<Long> itemQueue = itemSlideWindowMap.get(itemKey);synchronized(itemQueue) { // 清空 itemQueue.clear();} }}}/** * * @methodName: putItemkey * @description: 更新對象key的計數 * @param itemKey: 對象key * @param timeMillis : 時間戳,毫秒數,如為滑窗類計數器,使用此參數值 * @history: * ------------------------------------------------------------------------------ * dateversionmodifierremarks * ------------------------------------------------------------------------------ * 2021/08/031.0.0sheng.zheng初版 * 2021/08/081.0.1sheng.zheng支持多種類型計數器 * */public void putItemkey(String itemKey,Long timeMillis) {if (this.counterType == 1) { // 如果為計數器類型 if (itemMap.containsKey(itemKey)) {// 更新值,加鎖保護synchronized(itemMap) { Integer value = itemMap.get(itemKey); // 計數器+1 value ++; itemMap.put(itemKey, value);} }else {// 新key值,加鎖保護synchronized(itemMap) { itemMap.put(itemKey, 1);} }}else if(this.counterType == 2){ // 如果為滑窗類型 if (itemSlideWindowMap.containsKey(itemKey)) {Deque<Long> itemQueue = itemSlideWindowMap.get(itemKey);// 加鎖保護synchronized(itemQueue) { // 加入 itemQueue.add(timeMillis);} }else {// 新key值,加鎖保護Deque<Long> itemQueue = new ArrayDeque<Long>();synchronized(itemSlideWindowMap) { // 加入映射表 itemSlideWindowMap.put(itemKey, itemQueue); itemQueue.add(timeMillis);} }}else if(this.counterType == 3){ // 如果為滑窗+數量類型 if (itemSlideWindowMap.containsKey(itemKey)) {Deque<Long> itemQueue = itemSlideWindowMap.get(itemKey);// 加鎖保護synchronized(itemQueue) { Long head = 0L; // 循環處理頭部數據 while(true) {// 取得頭部數據head = itemQueue.peekFirst();if (head == null || timeMillis - head <= this.windowSize) { break;}// 移除頭部itemQueue.remove(); } // 加入新數據 itemQueue.add(timeMillis);} }else {// 新key值,加鎖保護Deque<Long> itemQueue = new ArrayDeque<Long>();synchronized(itemSlideWindowMap) { // 加入映射表 itemSlideWindowMap.put(itemKey, itemQueue); itemQueue.add(timeMillis);} }}}/** * * @methodName: clear * @description: 清空字典 * @history: * ------------------------------------------------------------------------------ * dateversionmodifierremarks * ------------------------------------------------------------------------------ * 2021/08/031.0.0sheng.zheng初版 * 2021/08/081.0.1sheng.zheng支持多種類型計數器 * */public void clear() {if (this.counterType == 1) {// 如果為計數器類型synchronized(this) {itemMap.clear();}}else if(this.counterType == 2){// 如果為滑窗類型synchronized(this) {itemSlideWindowMap.clear();}}else if(this.counterType == 3){// 如果為滑窗+數量類型synchronized(this) {itemSlideWindowMap.clear();}}}}2.3、調用

  要調用計數器,只需在應用類中添加DacService對象,如:

public class DataCommonService {// 數據訪問計數服務類,時間滑動窗口,窗口寬度60秒protected DacService dacService = new DacService(2,0,60000);/** * * @methodName: procNoClassData * @description: 對象組key對應的數據不存在時的處理 * @param classKey: 對象組key * @return: 數據加載成功,返回true,否則為false * @history: * ------------------------------------------------------------------------------ * dateversionmodifierremarks * ------------------------------------------------------------------------------ * 2021/08/081.0.0sheng.zheng初版 * */protected boolean procNoClassData(Object classKey) {boolean bRet = false;String key = getCombineKey(null,classKey);Long currentTime = System.currentTimeMillis();// 判斷計數器是否將滿if (dacService.isItemKeyFull(key,currentTime)) {// 如果計數將滿// 復位dacService.resetItemKey(key);// 從數據庫加載分組數據項bRet = loadGroupItems(classKey);}dacService.putItemkey(key,currentTime);return bRet;}/** * * @methodName: procNoItemData * @description: 對象key對應的數據不存在時的處理 * @param itemKey: 對象key * @param classKey: 對象組key * @return: 數據加載成功,返回true,否則為false * @history: * ------------------------------------------------------------------------------ * dateversionmodifierremarks * ------------------------------------------------------------------------------ * 2021/08/081.0.0sheng.zheng初版 * */protected boolean procNoItemData(Object itemKey, Object classKey) {// 如果itemKey不存在boolean bRet = false;String key = getCombineKey(itemKey,classKey);Long currentTime = System.currentTimeMillis();if (dacService.isItemKeyFull(key,currentTime)) {// 如果計數將滿// 復位dacService.resetItemKey(key);// 從數據庫加載數據項bRet = loadItem(itemKey, classKey);}dacService.putItemkey(key,currentTime);return bRet;}/** * * @methodName: getCombineKey * @description: 獲取組合key值 * @param itemKey: 對象key * @param classKey: 對象組key * @return: 組合key * @history: * ------------------------------------------------------------------------------ * dateversionmodifierremarks * ------------------------------------------------------------------------------ * 2021/08/081.0.0sheng.zheng初版 * */protected String getCombineKey(Object itemKey, Object classKey) {String sItemKey = (itemKey == null ? '' : itemKey.toString());String sClassKey = (classKey == null ? '' : classKey.toString());String key = '';if (!sClassKey.isEmpty()) {key = sClassKey;}if (!sItemKey.isEmpty()) {if (!key.isEmpty()) {key += '-' + sItemKey;}else {key = sItemKey;}}return key;}}

  procNoClassData方法:分組數據不存在時的處理。procNoItemData方法:單個數據項不存在時的處理。

  主從關系在數據庫中,較為常見,因此針對分組數據和單個對象key分別編寫了方法;如果key的個數超過2個,可以類似處理。

作者:阿拉伯1999 出處:http://www.cnblogs.com/alabo1999/ 本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利. 養成良好習慣,好文章隨手頂一下。

到此這篇關于Spring Boot實現數據訪問計數器方案詳解的文章就介紹到這了,更多相關Spring Boot數據訪問計數器內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Spring
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
丝袜亚洲另类欧美| 国精品产品一区| 亚洲精一区二区三区| 欧美色综合网| 中文字幕一区久| 影音先锋国产精品| 国产毛片精品| 精品国模一区二区三区| 亚洲小说春色综合另类电影| 欧美三区不卡| 视频福利一区| 奇米狠狠一区二区三区| 日韩亚洲一区在线| 久久电影一区| 麻豆91精品91久久久的内涵| 欧美另类专区| 国产亚洲一卡2卡3卡4卡新区| 日韩成人亚洲| 午夜亚洲福利| 欧美精品高清| 日本aⅴ亚洲精品中文乱码| 女生影院久久| 日韩精品社区| 99成人在线视频| 国产精品亚洲二区| 欧美日韩国产综合网| 国产探花在线精品| 精品在线91| 欧美91在线|欧美| 亚洲欧美日本日韩| 日本一二区不卡| 国产亚洲福利| 中国字幕a在线看韩国电影| 婷婷精品久久久久久久久久不卡| 黄色在线观看www| 日本va欧美va欧美va精品| 亚洲最新无码中文字幕久久| 久久久久久自在自线| а√在线中文在线新版| 99视频精品视频高清免费| 国产亚洲毛片在线| 欧美激情三区| 欧美特黄一区| 国产99久久| 欧美在线日韩| 国产91精品对白在线播放| 亚洲免费一区二区| 免费在线亚洲欧美| 国产精品亚洲综合久久| 秋霞国产精品| 你懂的国产精品永久在线| 亚洲精品进入| 99re国产精品| 久久人人88| 久久uomeier| 国产极品一区| 亚洲精选91| 99国产精品99久久久久久粉嫩| 91av亚洲| 久久午夜影院| 国产探花一区在线观看| 日韩视频二区| 日韩精品永久网址| 国产精品大片| 97se亚洲| 日韩欧美在线精品| 免费观看日韩电影| 亚洲免费网址| 日韩视频在线一区二区三区 | 国产66精品| 国产精品一区高清| 日韩国产在线观看一区| 日韩在线a电影| 亚洲在线成人| 午夜电影亚洲| 亚洲精品一区二区在线看| 蜜桃精品在线| 日韩另类视频| 日韩欧美字幕| 亚洲成人av观看| 精品高清久久| 国产精品v一区二区三区| 日本成人在线视频网站| 日韩在线视频一区二区三区| 老司机精品久久| 免费久久99精品国产自在现线| 欧美日韩一区二区三区视频播放| 日本免费一区二区三区四区| 国模精品一区| 欧美韩日一区| 色婷婷久久久| 国产一区日韩欧美| 2023国产精品久久久精品双| 自拍日韩欧美| 亚洲一区网站| 水野朝阳av一区二区三区| 免费看日韩精品| 亚洲男人在线| 91成人精品在线| 麻豆精品少妇| av中文资源在线资源免费观看| 青青青免费在线视频| 成人精品亚洲| 合欧美一区二区三区| 午夜在线播放视频欧美| 在线亚洲自拍| 在线一区二区三区视频| 日韩不卡在线观看日韩不卡视频| 久久国际精品| 国产一区二区三区91| 欧美香蕉视频| 国内精品福利| 在线综合亚洲| 亚洲理论在线| 国产精品中文字幕制服诱惑| 麻豆免费精品视频| 日韩欧美一区二区三区免费观看| 91精品1区| 亚洲精品综合| 国产精品啊啊啊| 亚洲综合在线电影| 亚洲欧美视频| 国产精品jk白丝蜜臀av小说| 久久青青视频| 美女91精品| 国产精品啊v在线| 日韩免费看片| 亚洲免费成人| 国产精品欧美大片| 肉色欧美久久久久久久免费看| 国产免费成人| 国产精品jk白丝蜜臀av小说| 日韩精品欧美| 亚欧成人精品| 国产精品久久久久蜜臀 | se01亚洲视频| 免费的成人av| 久久亚洲国产精品尤物| 99久久99久久精品国产片果冰| 亚洲欧洲另类| 国产三级精品三级在线观看国产| 国产日韩电影| 中文字幕亚洲精品乱码| 韩国女主播一区二区三区| 女主播福利一区| 国产精品极品在线观看| 国产一区欧美| 国产精品一区二区美女视频免费看| 亚洲四虎影院| 日韩高清不卡在线| 日韩欧美一区免费| 亚洲日产av中文字幕| 97国产成人高清在线观看| 日韩精品一级二级| 成人午夜亚洲| 免费看欧美美女黄的网站| 精品国产不卡| 夜夜嗨一区二区三区| 精品国产三区在线| 综合一区二区三区| 久久视频一区| 国产精东传媒成人av电影| 日韩视频一区二区三区在线播放免费观看| 国产精品分类| 日韩影院免费视频| 日韩福利一区| 国产伦理久久久久久妇女| 欧美 日韩 国产一区二区在线视频| 久久激情av| 午夜精品一区二区三区国产| 国产一精品一av一免费爽爽| 最新亚洲激情| 鲁鲁在线中文| 国产欧美自拍| 丝袜美腿一区二区三区| 欧美成a人国产精品高清乱码在线观看片在线观看久 | 日韩精品一区二区三区免费观影 | 日本高清不卡一区二区三区视频 | 香蕉精品视频在线观看| 免费视频一区二区三区在线观看| 亚洲综合日本| 精品丝袜在线| 免费在线播放第一区高清av| 美美哒免费高清在线观看视频一区二区| 9999国产精品| 国产乱人伦丫前精品视频| 亚洲精品电影| 黑森林国产精品av| 国产精品久久久久77777丨| 最近国产精品视频| 一区在线免费| 成人午夜国产| 国产成人免费精品| 国产精品久久| 青青草国产精品亚洲专区无| 亚洲一区国产| 午夜精品亚洲| 亚洲福利久久| 视频二区不卡| 国产h片在线观看|