用二进制控制多状态及相应SQL语句教程

前言

在一般的项目中,经常会有各种状态的要求的场景。比如一个论坛,用户账户会有激活、删除、冻结、手机绑定、邮箱绑定等多种状态,如果没个状态都在数据库中作一个字段,那么会很繁琐。而且代码实现也会很麻烦。因此,本文就会引导大家使用二进制来表示及控制多状态。

正文

二进制表示多状态的原理就是每个bit位对应一个状态,0和1来表示该状态的false和true。Java中,int型变量是32位,及最多可以表示32中状态。然而,我们一般并不需要过多状态。

例:MySQL字段’ACCOUNT_STATUS’,对应DO类中的属性’accountStatus’

状态定义

1
2
3
4
5
6
7
bit0:激活状态,0-未激活,1-已激活;
bit1:实名认证状态:0-未认证,1-已认证;
bit2:删除状态,0-未删除,1-已删除;
bit3:冻结禁用状态:0-未冻结,1-已冻结;
bit4:手机验证状态:0-未验证,1-已验证;
bit5:邮箱验证状态:0-未验证,1-已验证;
bit6:Google验证状态:0-未验证,1-已验证;

状态值示例

状态int值 二进制 说明
1 0000 0001 已激活;
5 0000 0101 已激活;已删除;
97 1100 0001 已激活;邮箱已验证;谷歌已验证;

Java定义示例

实现一个账户状态java类,及一个内部账户状态枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/**
* 账户状态类
*/
public class AccountStatusBean {
/** 用户状态值 */
private int status;
/** 已激活 */
private boolean activated;
/** 已认证 */
private boolean verified;
/** 已删除 */
private boolean deleted;
/** 已冻结(已禁用)*/
private boolean frozen;
/** 手机已验证 */
private boolean phoneVerified;
/** 邮箱已验证 */
private boolean emailVerified;
/** 谷歌已验证 */
private boolean googleVerified;

/**
* 获取用户状态的实际意义对象
* @param accountStatus 状态值
*/
public AccountStatusBean(int accountStatus) {
this.status = accountStatus;
this.activated = AccountStatusEnum.IS_ACTIVATED.status(accountStatus);
this.verified = AccountStatusEnum.IS_VERIFIED.status(accountStatus);
this.deleted = AccountStatusEnum.IS_DELETED.status(accountStatus);
this.frozen = AccountStatusEnum.IS_FROZEN.status(accountStatus);
this.phoneVerified = AccountStatusEnum.IS_VALIDATED_PHONE.status(accountStatus);
this.emailVerified = AccountStatusEnum.IS_VALIDATED_EMAIL.status(accountStatus);
this.googleVerified = AccountStatusEnum.IS_VALIDATED_GOOGLE.status(accountStatus);
}

/**
* 禁止直接修改状态值
* @param status 状态值
*/
private void setStatus(int status) {
this.status = status;
}

/**
* 账户状态枚举
*/
public enum AccountStatusEnum {
// 激活
IS_ACTIVATED((byte) 0x01, "activated"),
// 实名认证
IS_VERIFIED((byte) 0x02, "authorized"),
// 删除
IS_DELETED((byte) 0x04, "deleted"),
// 冻结
IS_FROZEN((byte) 0x08, "frozen"),
// 手机验证
IS_VALIDATED_PHONE((byte) 0x10, "validatedPhone"),
// 邮箱验证
IS_VALIDATED_EMAIL((byte) 0x20, "validatedEmail"),
// 谷歌验证
IS_VALIDATED_GOOGLE((byte) 0x40, "validatedGoogle");

AccountStatusEnum(byte code, String msg) {
this.code = code;
this.msg = msg;
}

/**
* 16进制形式(转成二进制理解)
*/
private byte code;
private String msg;

/**
* 获取对应的状态
* @param accountStatus 账户的状态值
* @return 该属性的状态Boolean结果
*/
public boolean status(int accountStatus) {
return (accountStatus & this.code) == this.code;
}

/**
* 修改某状态置
* @param accountStatus 账户的原状态值
* @param status true-1,false-0
* @return 账户的新状态值
*/
public int change(int accountStatus, boolean status) {
if (status) {
return setTrue(accountStatus);
} else {
return setFalse(accountStatus);
}
}

/**
* 将某状态置true / 1
* @param accountStatus 账户的原状态值
* @return 账户的新状态值
*/
public int setTrue(int accountStatus) {
accountStatus = this.code | accountStatus;
return accountStatus;
}

/**
* 将某状态置false / 0
* @param accountStatus 原状态值
* @return 新状态值
*/
public int setFalse(int accountStatus) {
accountStatus = (~this.code) & accountStatus;
return accountStatus;
}

/**
* 获取修改状态时,对应的update条件
* @param status 目标状态
* @return sql的update语句中,=右边的值的一部分。
*/
public String updateSql(boolean status) {
String condition = "";
if (status) {
condition += " | ";
} else {
condition += " & ~";
}
condition += this.code;
return condition;
}

/**
* @return 二进制对应的byte
*/
public byte code() {
return this.code;
}

public String msg() {
return this.msg;
}
}
}

Java使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 获取该账户对象
AdminCustomerInfoDO adminCustomerInfoDO = adminCustomerInfoDao.selectById(id);
Integer accountStatus = adminCustomerInfoDO.getAccountStatus();
// 解析该账户状态
AccountStatusBean accountStatusBean = new AccountStatusBean(accountStatus.intValue());
boolean deleted = accountStatusBean.isDeleted();
if (deleted) {
// 已删除
}
boolean frozen = accountStatusBean.isFrozen();
if (frozen) {
// 已冻结
}
boolean activated = accountStatusBean.isActivated();
if (activated) {
// 已激活
}

改:直接修改状态字段int值

1
2
3
4
5
6
7
8
9
// 激活该账户
accountStatusBean.setActivated(true);
// 邮箱已绑定
accountStatusBean.setEmailVerified(true);
// 更新
AdminCustomerInfoDO updateDO = new AdminCustomerInfoDO();
updateDO.setAccountStatus(accountStatusBean.getStatus());
// 更新数据库
int update = adminCustomerInfoDao.update(updateDO);

改:修改某个状态

1
2
// 改为激活状态
String statusSql = AccountStatusBean.AccountStatusEnum.IS_ACTIVATED.updateSql(true);
1
2
<!-- sql语句中的set语句 -->
set ACCOUNT_STATUS = (ACCOUNT_STATUS ${statusSql})

MySQL语句示例

查:查询某状态下的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#已激活
SELECT * FROM admin_customer_info WHERE ACCOUNT_STATUS = (ACCOUNT_STATUS | 1)
#未激活
SELECT * FROM admin_customer_info WHERE ACCOUNT_STATUS = (ACCOUNT_STATUS & ~ 1)
#已认证
SELECT * FROM admin_customer_info WHERE ACCOUNT_STATUS = (ACCOUNT_STATUS | 2)
#未认证
SELECT * FROM admin_customer_info WHERE ACCOUNT_STATUS = (ACCOUNT_STATUS & ~ 2)
#已删除
SELECT * FROM admin_customer_info WHERE ACCOUNT_STATUS = (ACCOUNT_STATUS | 4)
#未删除
SELECT * FROM admin_customer_info WHERE ACCOUNT_STATUS = (ACCOUNT_STATUS & ~ 4)
#已冻结
SELECT * FROM admin_customer_info WHERE ACCOUNT_STATUS = (ACCOUNT_STATUS | 8)
#未冻结
SELECT * FROM admin_customer_info WHERE ACCOUNT_STATUS = (ACCOUNT_STATUS & ~ 8)
#已完成手机验证
SELECT * FROM admin_customer_info WHERE ACCOUNT_STATUS = (ACCOUNT_STATUS | 16)
#未完成手机验证
SELECT * FROM admin_customer_info WHERE ACCOUNT_STATUS = (ACCOUNT_STATUS & ~ 16)
#已完成邮箱验证
SELECT * FROM admin_customer_info WHERE ACCOUNT_STATUS = (ACCOUNT_STATUS | 32)
#未完成邮箱验证
SELECT * FROM admin_customer_info WHERE ACCOUNT_STATUS = (ACCOUNT_STATUS & ~ 32)
#已完成谷歌验证
SELECT * FROM admin_customer_info WHERE ACCOUNT_STATUS = (ACCOUNT_STATUS | 64)
#未完成谷歌验证
SELECT * FROM admin_customer_info WHERE ACCOUNT_STATUS = (ACCOUNT_STATUS & ~ 64)

改:修改单独的某个状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#激活
UPDATE admin_customer_info set ACCOUNT_STATUS = (ACCOUNT_STATUS | 1)
#取消激活
UPDATE admin_customer_info set ACCOUNT_STATUS = (ACCOUNT_STATUS & ~ 1)
#认证
UPDATE admin_customer_info set ACCOUNT_STATUS = (ACCOUNT_STATUS | 2)
#取消认证
UPDATE admin_customer_info set ACCOUNT_STATUS = (ACCOUNT_STATUS & ~ 2)
#删除
UPDATE admin_customer_info set ACCOUNT_STATUS = (ACCOUNT_STATUS | 4)
#取消删除
UPDATE admin_customer_info set ACCOUNT_STATUS = (ACCOUNT_STATUS & ~ 4)
#冻结
UPDATE admin_customer_info set ACCOUNT_STATUS = (ACCOUNT_STATUS | 8)
#取消冻结
UPDATE admin_customer_info set ACCOUNT_STATUS = (ACCOUNT_STATUS & ~ 8)
#手机验证
UPDATE admin_customer_info set ACCOUNT_STATUS = (ACCOUNT_STATUS | 16)
#解除手机验证
UPDATE admin_customer_info set ACCOUNT_STATUS = (ACCOUNT_STATUS & ~ 16)
#邮箱验证
UPDATE admin_customer_info set ACCOUNT_STATUS = (ACCOUNT_STATUS | 32)
#解除邮箱验证
UPDATE admin_customer_info set ACCOUNT_STATUS = (ACCOUNT_STATUS & ~ 32)
#谷歌验证
UPDATE admin_customer_info set ACCOUNT_STATUS = (ACCOUNT_STATUS | 64)
#解除谷歌验证
UPDATE admin_customer_info set ACCOUNT_STATUS = (ACCOUNT_STATUS & ~ 64)

结尾

第一次写博客,个人感觉这个知识还是挺有用的、挺好玩的。写的不好,还请谅解。

有趣的灵魂终会相聚;

有梦想的人就不会死;

共勉;