教你巧用mysql位運(yùn)算解決多選值存儲(chǔ)的問題
一.問題場(chǎng)景
工作中經(jīng)常遇到多選值存儲(chǔ)問題,例如:用戶有多種認(rèn)證方式,密碼認(rèn)證、短信認(rèn)證、掃碼認(rèn)證等,一個(gè)用戶可能只開啟了其中某幾種認(rèn)證方式。
二. 場(chǎng)景分析
比較容易理解的兩種實(shí)現(xiàn)方式,多字段存儲(chǔ)、單個(gè)字段拼接存儲(chǔ)。
1.多字段存儲(chǔ)
每種認(rèn)證方式用一個(gè)字段存儲(chǔ),0表示未開啟,1表示已開啟。
缺點(diǎn):每增加一種認(rèn)證方式都需要添加一個(gè)表字段,擴(kuò)展性差。
2.單字段拼接
單字段存儲(chǔ),已開啟的認(rèn)證方式用逗號(hào)(或其他分割符)拼接。例如:開始了密碼認(rèn)證和短信認(rèn)證,則存儲(chǔ)為:密碼認(rèn)證,短信認(rèn)證。
缺點(diǎn):不利于查詢,需要使用模糊查詢,搞不好會(huì)影響性能。
三.巧用位運(yùn)算
1.概述
參考Linux權(quán)限控制思路,將每種認(rèn)證方式對(duì)應(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存儲(chǔ)時(shí)使用單字段(auth_method)int類型存儲(chǔ),如果開啟了多種認(rèn)證方式將多種認(rèn)證方式對(duì)應(yīng)的枚舉數(shù)值相加后存儲(chǔ),例如開啟了密碼認(rèn)證和短信認(rèn)證,則存儲(chǔ)為3(1+2)。
2.sql查詢
## 例1:判斷用戶是否開啟了密碼認(rèn)證--1 (滿足條件時(shí)返回查詢結(jié)果,沒有滿足條件時(shí)返回為空) 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存儲(chǔ)值解析成多種認(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ì)算后得到存儲(chǔ)值
* @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)了單個(gè)字段存儲(chǔ)不同的認(rèn)證狀態(tài),增加一個(gè)新的認(rèn)證方式時(shí)只需要添加一個(gè)枚舉值。不僅可以節(jié)省存儲(chǔ)空間,大大增加了可擴(kuò)展性,對(duì)性能幾乎沒有影響。
附MySQL的支持6種位運(yùn)算
| 符號(hào) | 含義 |
|---|---|
| a|b | 位或 |
| a&b | 位與 |
| a^b | 位異或 |
| ~a | 位取反 |
| a<<b | 位左移 |
| a>>b | 位右移 |
總結(jié)
到此這篇關(guān)于教你巧用mysql位運(yùn)算解決多選值存儲(chǔ)問題的文章就介紹到這了,更多相關(guān)mysql位運(yùn)算解決多選值存儲(chǔ)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在Windows上使用ZIP包安裝MySQL的詳細(xì)步驟
本文詳細(xì)介紹了在Windows上使用官方ZIP包安裝MySQL的步驟,包括下載、解壓、配置環(huán)境變量、創(chuàng)建配置文件、初始化MySQL、安裝服務(wù)、啟動(dòng)服務(wù)、登錄并修改root密碼以及驗(yàn)證連接,需要的朋友可以參考下2025-02-02
mysql連接數(shù)設(shè)置操作方法(Too many connections)
下面小編就為大家?guī)硪黄猰ysql連接數(shù)設(shè)置操作方法(Too many connections)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-03-03
如何添加一個(gè)mysql用戶并給予權(quán)限詳解
在很多時(shí)候我們并不會(huì)直接利用mysql的root用戶進(jìn)行項(xiàng)目的開發(fā),一般我們都會(huì)創(chuàng)建一個(gè)具有部分權(quán)限的用戶,下面這篇文章主要給大家介紹了關(guān)于如何添加一個(gè)mysql用戶并給予權(quán)限的相關(guān)資料,需要的朋友可以參考下2023-03-03
MySQL性能優(yōu)化的最佳20+條經(jīng)驗(yàn)
這篇文章主要為大家詳細(xì)介紹了MySQL性能優(yōu)化的最佳20+條經(jīng)驗(yàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09
Mysql分組查詢每組最新的一條數(shù)據(jù)的五種實(shí)現(xiàn)過程
本文介紹了五種在MySQL中獲取每個(gè)分組最新一條數(shù)據(jù)的方法,包括子查詢和JOIN、窗口函數(shù)、變量、聚合函數(shù)和子查詢以及使用DISTINCT關(guān)鍵字,推薦使用子查詢和JOIN操作或窗口函數(shù),避免使用變量2024-11-11
Mysql聯(lián)合查詢UNION和Order by同時(shí)使用報(bào)錯(cuò)問題的解決辦法
很多朋友剛使用聯(lián)合查詢UNION的時(shí)候常常會(huì)理所當(dāng)然的將聯(lián)合查詢理解為把沒一個(gè)子查詢的結(jié)果集組合成一個(gè)大的結(jié)果集2014-04-04

