教你巧用mysql位運(yùn)算解決多選值存儲的問題
一.問題場景
工作中經(jīng)常遇到多選值存儲問題,例如:用戶有多種認(rèn)證方式,密碼認(rèn)證、短信認(rèn)證、掃碼認(rèn)證等,一個用戶可能只開啟了其中某幾種認(rèn)證方式。
二. 場景分析
比較容易理解的兩種實(shí)現(xiàn)方式,多字段存儲、單個字段拼接存儲。
1.多字段存儲
每種認(rèn)證方式用一個字段存儲,0表示未開啟,1表示已開啟。
缺點(diǎn):每增加一種認(rèn)證方式都需要添加一個表字段,擴(kuò)展性差。
2.單字段拼接
單字段存儲,已開啟的認(rèn)證方式用逗號(或其他分割符)拼接。例如:開始了密碼認(rèn)證和短信認(rèn)證,則存儲為:密碼認(rèn)證,短信認(rèn)證。
缺點(diǎn):不利于查詢,需要使用模糊查詢,搞不好會影響性能。
三.巧用位運(yùn)算
1.概述
參考Linux權(quán)限控制思路,將每種認(rèn)證方式對應(yīng)到二進(jìn)制位中,例如:密碼認(rèn)證–10000000,短信認(rèn)證–01000000,掃碼認(rèn)證–00100000,然后將其轉(zhuǎn)換成10進(jìn)制,密碼認(rèn)證–1, 短信認(rèn)證–2,掃碼認(rèn)證–4。Mysql存儲時使用單字段(auth_method)int類型存儲,如果開啟了多種認(rèn)證方式將多種認(rèn)證方式對應(yīng)的枚舉數(shù)值相加后存儲,例如開啟了密碼認(rèn)證和短信認(rèn)證,則存儲為3(1+2)。
2.sql查詢
## 例1:判斷用戶是否開啟了密碼認(rèn)證--1 (滿足條件時返回查詢結(jié)果,沒有滿足條件時返回為空) Select * from user where auth_method & 1; ## 例2:判斷用戶是否開啟了密碼認(rèn)證 + 短信認(rèn)證 (1+2) Select * from user where auth_method & 3; ## 例2:判斷用戶是否開啟了密碼認(rèn)證 + 短信認(rèn)證 + 掃碼認(rèn)證 (1+2+4) Select * from user where auth_method & 7;
3.Java解析與計(jì)算
import com.google.common.collect.Lists; import lombok.Getter; import org.springframework.util.CollectionUtils; import java.util.Arrays; import java.util.List; @Getter public enum AuthMethodEnum { PASSWORD(1, "密碼認(rèn)證"), SMS(2, "短信認(rèn)證"), QR_CODE(4, "掃碼認(rèn)證"); private Integer method; private String name; AuthMethodEnum(Integer method, String name) { this.method = method; this.name = name; } /** * 將mysql存儲值解析成多種認(rèn)證方式 * @param method * @return */ public static List<Integer> parseAuthMethod(Integer method) { List<Integer> list = Lists.newArrayList(); if (null == method) { return list; } AuthMethodEnum[] arr = AuthMethodEnum.values(); // 需要先將method從大到小排序 Arrays.sort(arr, (o1, o2) -> { if (o1.method > o2.method) { return -1; } else { return 0; } }); for (AuthMethodEnum e : arr) { if (method >= e.method) { list.add(e.method); method = method - e.method; } } return list; } /** * 將任意種認(rèn)證方式計(jì)算后得到存儲值 * @param methods * @return */ public static Integer calculateAuthMethod(List<Integer> methods) { if (CollectionUtils.isEmpty(methods)) { return 0; } return methods.stream().mapToInt(p -> p).sum(); } public static void main(String[] args) { System.out.println(parseAuthMethod(8)); } }
4.總結(jié)
通過位運(yùn)算的轉(zhuǎn)換,實(shí)現(xiàn)了單個字段存儲不同的認(rèn)證狀態(tài),增加一個新的認(rèn)證方式時只需要添加一個枚舉值。不僅可以節(jié)省存儲空間,大大增加了可擴(kuò)展性,對性能幾乎沒有影響。
附MySQL的支持6種位運(yùn)算
符號 | 含義 |
---|---|
a|b | 位或 |
a&b | 位與 |
a^b | 位異或 |
~a | 位取反 |
a<<b | 位左移 |
a>>b | 位右移 |
總結(jié)
到此這篇關(guān)于教你巧用mysql位運(yùn)算解決多選值存儲問題的文章就介紹到這了,更多相關(guān)mysql位運(yùn)算解決多選值存儲內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mysql技巧:提高插入數(shù)據(jù)(添加記錄)的速度
這篇文章主要介紹了mysql技巧:提高插入數(shù)據(jù)(添加記錄)的速度,需要的朋友可以參考下2014-12-12MySQL 8.0.19安裝詳細(xì)教程(windows 64位)
這篇文章主要介紹了MySQL 8.0.19安裝詳細(xì)教程(windows 64位),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-10-10Explain命令在優(yōu)化查詢中的實(shí)際應(yīng)用
在MySQL中,EXPLAIN命令是一種非常重要的查詢優(yōu)化工具,它可以幫助我們分析SQL查詢語句的執(zhí)行計(jì)劃,以及如何優(yōu)化它們。本文介紹了Explain命令在優(yōu)化查詢中的實(shí)際應(yīng)用,感興趣的小伙伴可以參考閱讀2023-04-04MySQL去重中distinct和group?by的區(qū)別淺析
今天無意中聽到有同事在討論,distinct和group by有什么區(qū)別,下面這篇文章主要給大家介紹了關(guān)于MySQL去重中distinct和group?by區(qū)別的相關(guān)資料,需要的朋友可以參考下2022-11-11MySQL實(shí)現(xiàn)批量插入測試數(shù)據(jù)的方式總結(jié)
在開發(fā)過程中經(jīng)常需要一些測試數(shù)據(jù),?這個時候如果手敲的話,?十行二十行還好,?多了就很死亡了,?接下來介紹兩種常用的MySQL測試數(shù)據(jù)批量生成方式,希望對大家有所幫助2023-05-05Linux7.6二進(jìn)制安裝Mysql8.0.27詳細(xì)操作步驟
大家好,本篇文章主要講的是Linux7.6二進(jìn)制安裝Mysql8.0.27詳細(xì)操作步驟,感興趣的同學(xué)快來看一看吧,希望對你起到幫助2021-11-11MyEclipse連接Mysql數(shù)據(jù)庫的方法(一)
這篇文章主要介紹了MyEclipse連接Mysql數(shù)據(jù)庫的方法(一)的相關(guān)資料,非常實(shí)用,具有參考價值,需要的朋友可以參考下2016-05-05MySQL數(shù)據(jù)庫開啟、關(guān)閉、查看函數(shù)功能的方法
這篇文章主要介紹了MySQL數(shù)據(jù)庫開啟、關(guān)閉、查看函數(shù)功能的方法,本文為解決一個錯誤總結(jié)而來,錯誤信息本文一同給出,需要的朋友可以參考下2014-10-10mysql正確刪除數(shù)據(jù)的方法(drop,delete,truncate)
這篇文章主要給大家介紹了關(guān)于mysql正確刪除數(shù)據(jù)的相關(guān)資料,DELETE語句是MySQL中最常用的刪除數(shù)據(jù)的方式之一,但也有幾種其他方法來實(shí)現(xiàn),需要的朋友可以參考下2023-10-10Spring中的InitializingBean和SmartInitializingSingleton的區(qū)別詳解
這篇文章主要介紹了Spring中的InitializingBean和SmartInitializingSingleton的區(qū)別詳解,InitializingBean只有一個接口方法afterPropertiesSet(),在BeanFactory初始化完這個bean,并且把bean的參數(shù)都注入成功后調(diào)用一次afterPropertiesSet()方法,需要的朋友可以參考下2024-01-01