av一区二区在线观看_亚洲男人的天堂网站_日韩亚洲视频_在线成人免费_欧美日韩精品免费观看视频_久草视

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

Spring Boot實(shí)現(xiàn)數(shù)據(jù)訪問(wèn)計(jì)數(shù)器方案詳解

瀏覽:5日期:2023-06-26 18:28:45
目錄1、數(shù)據(jù)訪問(wèn)計(jì)數(shù)器2、代碼實(shí)現(xiàn)2.1、方案說(shuō)明2.2、代碼2.3、調(diào)用1、數(shù)據(jù)訪問(wèn)計(jì)數(shù)器

  在Spring Boot項(xiàng)目中,有時(shí)需要數(shù)據(jù)訪問(wèn)計(jì)數(shù)器。大致有下列三種情形:

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

2)時(shí)間滑動(dòng)窗口:設(shè)窗口寬度為T,如果窗口中尾幀時(shí)間與首幀時(shí)間差大于T,則表示計(jì)數(shù)器滿。

  例如使用redis緩存時(shí),使用key查詢r(jià)edis中數(shù)據(jù),如果有此key數(shù)據(jù),則返回對(duì)象數(shù)據(jù);如無(wú)此key數(shù)據(jù),則查詢數(shù)據(jù)庫(kù),但如果一直都無(wú)此key數(shù)據(jù),從而反復(fù)查詢數(shù)據(jù)庫(kù),顯然有問(wèn)題。此時(shí),可使用時(shí)間滑動(dòng)窗口,對(duì)于查詢的失敗的key,距離首幀T時(shí)間(如1分鐘)內(nèi),不再查詢數(shù)據(jù)庫(kù),而是直接返回?zé)o此數(shù)據(jù),直到新查詢的時(shí)間超過(guò)T,更新滑窗首幀為新時(shí)間,并執(zhí)行一次查詢數(shù)據(jù)庫(kù)操作。

3)時(shí)間滑動(dòng)窗口+計(jì)數(shù):這往往在需要進(jìn)行限流處理的場(chǎng)景使用。如T時(shí)間(如1分鐘)內(nèi),相同key的訪問(wèn)次數(shù)超過(guò)超過(guò)門限N,則表示計(jì)數(shù)器滿,此時(shí)進(jìn)行限流處理。

2、代碼實(shí)現(xiàn)2.1、方案說(shuō)明

1)使用字典來(lái)管理不同的key,因?yàn)椴煌膋ey需要單獨(dú)計(jì)數(shù)。

2)上述三種情況,使用類型屬性區(qū)分,并在構(gòu)造函數(shù)中進(jìn)行設(shè)置。

3)滑動(dòng)窗口使用雙向隊(duì)列Deque來(lái)實(shí)現(xiàn)。

4)考慮到訪問(wèn)并發(fā)性,讀取或更新時(shí),加鎖保護(hù)。

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

  要調(diào)用計(jì)數(shù)器,只需在應(yīng)用類中添加DacService對(duì)象,如:

public class DataCommonService {// 數(shù)據(jù)訪問(wèn)計(jì)數(shù)服務(wù)類,時(shí)間滑動(dòng)窗口,窗口寬度60秒protected DacService dacService = new DacService(2,0,60000);/** * * @methodName: procNoClassData * @description: 對(duì)象組key對(duì)應(yīng)的數(shù)據(jù)不存在時(shí)的處理 * @param classKey: 對(duì)象組key * @return: 數(shù)據(jù)加載成功,返回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();// 判斷計(jì)數(shù)器是否將滿if (dacService.isItemKeyFull(key,currentTime)) {// 如果計(jì)數(shù)將滿// 復(fù)位dacService.resetItemKey(key);// 從數(shù)據(jù)庫(kù)加載分組數(shù)據(jù)項(xiàng)bRet = loadGroupItems(classKey);}dacService.putItemkey(key,currentTime);return bRet;}/** * * @methodName: procNoItemData * @description: 對(duì)象key對(duì)應(yīng)的數(shù)據(jù)不存在時(shí)的處理 * @param itemKey: 對(duì)象key * @param classKey: 對(duì)象組key * @return: 數(shù)據(jù)加載成功,返回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)) {// 如果計(jì)數(shù)將滿// 復(fù)位dacService.resetItemKey(key);// 從數(shù)據(jù)庫(kù)加載數(shù)據(jù)項(xiàng)bRet = loadItem(itemKey, classKey);}dacService.putItemkey(key,currentTime);return bRet;}/** * * @methodName: getCombineKey * @description: 獲取組合key值 * @param itemKey: 對(duì)象key * @param classKey: 對(duì)象組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方法:分組數(shù)據(jù)不存在時(shí)的處理。procNoItemData方法:?jiǎn)蝹€(gè)數(shù)據(jù)項(xiàng)不存在時(shí)的處理。

  主從關(guān)系在數(shù)據(jù)庫(kù)中,較為常見(jiàn),因此針對(duì)分組數(shù)據(jù)和單個(gè)對(duì)象key分別編寫了方法;如果key的個(gè)數(shù)超過(guò)2個(gè),可以類似處理。

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

到此這篇關(guān)于Spring Boot實(shí)現(xiàn)數(shù)據(jù)訪問(wèn)計(jì)數(shù)器方案詳解的文章就介紹到這了,更多相關(guān)Spring Boot數(shù)據(jù)訪問(wèn)計(jì)數(shù)器內(nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Spring
相關(guān)文章:
主站蜘蛛池模板: 亚洲一区二区三区国产 | 日韩精品免费在线观看 | 中文字幕久久精品 | 在线国产一区 | 日韩欧美在线不卡 | 亚洲天堂一区 | 91精品国产乱码久久久久久久 | 日本欧美在线观看视频 | 自拍视频一区二区三区 | a毛片 | 欧美在线视频一区 | 欧美在线视频不卡 | 自拍偷拍在线视频 | 欧美精品一区二区在线观看 | 精品二三区 | 黄色网页在线 | 久草网免费 | 欧美日韩在线精品 | 可以免费看的毛片 | 97国产精品 | 欧美一区二区黄 | 亚洲人成在线播放 | 日日夜夜精品免费视频 | 精品国产乱码久久久久久牛牛 | 亚洲激情在线观看 | 日批日韩在线观看 | av在线播放一区二区 | 国产成人免费在线 | 激情福利视频 | 久久久久久久久久久福利观看 | 91精品国产色综合久久 | 欧美日韩一区在线 | 蜜桃免费av | 天天操夜夜拍 | 国产精品久久av | 国产精品久久一区二区三区 | 亚洲精品一区在线 | 天天色天天色 | 欧美一区二区三区视频在线 | 九九九久久国产免费 | 狠狠艹 |