面試官問一個數據表字段怎麼表示多種業務含義?我愣了五分鐘

歡迎你們關注公衆號「JAVA前線」查看更多精彩分享文章,主要包括源碼分析、實際應用、架構思惟、職場分享、產品思考等等,同時歡迎你們加我我的微信「java_front」一塊兒交流學習java

1 需求背景

在系統中用戶一共有三種角色:普通用戶,管理員,超級管理員,如今須要設計一張用戶角色表記錄這類信息。咱們不難設計出以下方案:面試

面試官問一個數據表字段怎麼表示多種業務含義?我愣了五分鐘

 

咱們使用1表示是,0表示否,那麼觀察上表不可貴出,用戶一有用超級管理員角色,用戶二具備管理員角色,用戶三具備普通用戶角色,用戶四同時具備三種角色。數據庫

若是此時新增長一種角色呢?那麼新增一個字段便可:微信

面試官問一個數據表字段怎麼表示多種業務含義?我愣了五分鐘

 

2 發現問題

按照上述作法進行表設計功能上是沒有問題的,優勢是容易理解結構清晰,可是咱們想想有沒有什麼問題?筆者遇到過以下問題:架構

在複雜業務環境一份數據可能會使用在不一樣的場景,例如上述數據存儲在MySQL數據庫,這一份數據還會被用在以下場景:源碼分析

  • 檢索數據須要同步一份到ES
  • 業務方使用此表經過Flink計算業務指標
  • 業務方訂閱此表Binlog消息進行業務處理

若是表結構發生變化,數據源之間就要從新進行對接,業務方也要進行代碼修改,這樣開發成本比較很是高。有沒有辦法避免此類問題?學習

3 解決方案

咱們能夠經過位圖法,這樣同一個字段能夠表示多個含義。首先設計以下數據表,userFlag字段先不填。this

面試官問一個數據表字段怎麼表示多種業務含義?我愣了五分鐘

 

咱們使用位圖法每個bit表示一種角色spa

面試官問一個數據表字段怎麼表示多種業務含義?我愣了五分鐘

 

咱們使用位圖法表示以下數據表設計

面試官問一個數據表字段怎麼表示多種業務含義?我愣了五分鐘

 

用戶一位圖以下十進制數值是4

面試官問一個數據表字段怎麼表示多種業務含義?我愣了五分鐘

 

用戶二位圖以下十進制數值是2

面試官問一個數據表字段怎麼表示多種業務含義?我愣了五分鐘

 

用戶三位圖以下十進制數值是1

面試官問一個數據表字段怎麼表示多種業務含義?我愣了五分鐘

 

用戶四位圖以下十進制數值是7

面試官問一個數據表字段怎麼表示多種業務含義?我愣了五分鐘

 

這時咱們能夠補齊數據表

面試官問一個數據表字段怎麼表示多種業務含義?我愣了五分鐘

 

4 位圖法詳解

本章節咱們分析位圖法方案一些關鍵節點。

4.1 枚舉定義

定義枚舉時不要直接定義爲一、二、4這類數字,而是採用位移方式定義,這樣使用者能夠明白設計者意圖。

/** * 用戶角色枚舉 * * @author JAVA前線 * */
public enum UserRoleEnum {

    // 1 -> 00000001
    NORMAL(1, "普通用戶"),

    // 2 -> 00000010
    MANAGER(1 << 1, "管理員"),

    // 4 -> 00000100
    SUPER(1 << 2, "超級管理員")

    ;

    private int code;
    private String description;

    private UserRoleEnum(Integer code, String description) {
        this.code = code;
        this.description = description;
    }

    public String getDescription() {
        return description;
    }

    public int getCode() {
        return this.code;
    }
}

4.2 維護角色

假設用戶已經具備普通用戶角色,咱們須要爲其增長管理員角色,這就是新增角色,與之對應還有刪除角色和查詢角色,這些操做須要用到爲位運算,說明詳見代碼註釋。

/** * 用戶角色枚舉 * * @author JAVA前線 * */
public enum UserRoleEnum {

    // 1 -> 00000001
    NORMAL(1, "普通用戶"),

    // 2 -> 00000010
    MANAGER(1 << 1, "管理員"),

    // 4 -> 00000100
    SUPER(1 << 2, "超級管理員")

    ;

    // 新增角色 -> 位或操做
    // oldRole -> 00000001 -> 普通用戶
    // addRole -> 00000010 -> 新增管理員
    // newRole -> 00000011 -> 普通用戶和管理員
    public static Integer addRole(Integer oldRole, Integer addRole) {
        return oldRole | addRole;
    }

    // 刪除角色 -> 位異或操做
    // oldRole -> 00000011 -> 普通用戶和管理員
    // delRole -> 00000010 -> 刪除管理員
    // newRole -> 00000001 -> 普通用戶
    public static Integer removeRole(Integer oldRole, Integer delRole) {
        return oldRole ^ delRole;
    }

    // 是否有某種角色 -> 位與操做
    // allRole -> 00000011 -> 普通用戶和管理員
    // qryRole -> 00000001 -> 是否有管理員角色
    // resRole -> 00000001 -> 有普通用戶角色
    public static boolean hasRole(Integer role, Integer queryRole) {
        return queryRole == (role & queryRole);
    }

    private int code;
    private String description;

    private UserRoleEnum(Integer code, String description) {
        this.code = code;
        this.description = description;
    }

    public String getDescription() {
        return description;
    }

    public int getCode() {
        return this.code;
    }

    public static void main(String[] args) {
        System.out.println(addRole(1, 2));
        System.out.println(removeRole(3, 1));
        System.out.println(hasRole(3, 1));
    }
}

4.3 數據查詢

假設在運營後臺查詢界面中,須要查詢具備普通用戶角色的用戶數據,咱們可使用SQL語句以下

select * from user_role where (user_flag & 1) = user_flag;
select * from user_role where (user_flag & b'0001') = user_flag;

使用MyBatis語句以下

<select id="selectByUserRole" resultMap="BaseResultMap" parameterType="java.util.Map">
  select * from user_role 
  where user_flag & #{userFlag} = #{userFlag}
</select>

<select id="selectByUserIdAndRole" resultMap="BaseResultMap" parameterType="java.util.Map">
  select * from user_role 
  where id = #{userId} and user_flag & #{userFlag} = #{userFlag}
</select>

 

5 文章總結

本文咱們從一個簡單案例開始,分析了直接新增字段優缺點,使用新增字段方法,筆者遇到最多的問題就是在複雜業務場景中,若是新增字段數據須要新增對接工做量,增長了開發成本。

咱們介紹了位圖法,這樣一個字段就能夠表示多個含義,減小了字段冗餘,節省了對接開發成本。固然位圖法也有缺點,其增長了代碼理解成本,數據庫字段含義不直觀,須要進行轉義,你們能夠根據需求場景選擇使用。

歡迎你們關注公衆號「JAVA前線」查看更多精彩分享文章,主要包括源碼分析、實際應用、架構思惟、職場分享、產品思考等等,同時歡迎你們加我我的微信「java_front」一塊兒交流學習

相關文章
相關標籤/搜索