一、介绍
1、实用性
项目中可能有很多开关,如果存成K-V类型的,存储比较占空间,根据key来批量查询也耗时。开关只有两个值,true或false,这和java的bit(0或1)非常类似,因此可以用一个bit来表示一个开关。如果数据库一个字段只存储一个bit,仍然解决不了上述问题,因此可以把多个比特位放在一起。如用一个bigint字段来存储比特位,bigint转成二进制最多可以存储62个bit,这样查询一个字段就能获取到62个开关。
2、基础
符号 | 描述 | 运算规则 |
---|---|---|
& | 与 | 两个位都为1时,结果才为1 |
| | 或 | 两个位都为0时,结果才为0 |
^ | 异或 | 两个位相同为0,相异为1 |
~ | 取反 | 0变1,1变0 |
<< | 左移 | 各二进位全部左移若干位,高位丢弃,低位补0 |
>> | 右移 | 各二进位全部右移若干位,高位补0或符号位补齐 |
0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1
3、实现
CREATE TABLE bits_table (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id varchar(20),
bit_value BIGINT UNSIGNED
);
关于bit的更新与查询,有两种方法,整体操作(int)或者按位操作bit。
默认值问题:我们一般认为0代表false 1代表true,如果某一位bit默认值需要为true,也有两种方法:刷数据初始化值都刷成1;或者在代码层面做标记,查询/更新做个取反。
二、java代码操作整体Long字段
更新时可以先在java代码使用位运算算出整个bigint,再更新这个bigint字段;
查询也可以查出整个bigint,在java代码中使用位运算计算某一位的值。
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
public class BitUtil {
public static int setBit(int options, int bitIndex) {
int val = 1 << bitIndex;
return options | val;
}
public static int unsetBit(int options, int bitIndex) {
int val = 1 << bitIndex;
return options & (~ val);
}
public static boolean isBitSetted(int options, int bitIndex) {
int val = 1 << bitIndex;
return (options & val) == val;
}
public static boolean isBitUnSetted(int options, int bitIndex) {
int val = 1 << bitIndex;
return (options & val) == 0;
}
public static boolean isSetted(long options, long bit) {
return (options & bit) == bit;
}
public static long set(long options, long bit) {
return options | bit;
}
public static long unset(long options, long bit) {
return options & (~bit);
}
public static long set(long options, long bit, boolean flag) {
if (flag) {
return set(options, bit);
} else {
return unset(options, bit);
}
}
public static boolean isSet(long options, long bit) {
return (options & bit) == bit;
}
public static void main(String[] args) {
UserDTO userDTO = getByUserId("zs");
long options = userDTO.getOptions;
//获取第7个开关的值
long index = 1L << 6;
boolean switchValue = BitUtil.isSet(options, index);
//设置第7个开关
switchValue = !switchValue;
options = BitUtil.set(
options,
index,
switchValue);
userDTO.setOptions(options);
updateUser(userDTO);
}
}
三、mysql按位操作
还是上面的表,也可以写SQL按位操作
1、插入
-- 1、插入一个8 位的 BIT 值
INSERT INTO bits_table (bit_value) VALUES (B'10101010');
2、查询并格式化为二进制输出
-- 2、查询并格式化输出,将 BIGINT 转换为 64 位的二进制字符串
SELECT
id,
bit_value,
CONCAT('b', LPAD(BIN(bit_value), 64, '0')) AS formatted_bit_value
FROM
bits_table;
查询结果:
CONCAT('b', LPAD(BIN(bit_value), 64, '0'))
用于将 bit_value
转换为一个以 'b' 开头的 64 位二进制字符串&