使用bit位进行标识 - pod4g/tool GitHub Wiki
一、 问题引出
我们以一个数据表的设计为例,比如,一个程序猿表(rd),含有3个字段
ID | Name | Skill |
---|---|---|
主键 | 程序猿名字 | 会的技能 |
一个程序猿假设他的Skill为下列技能的一种或几种:
- Java
- JavaScript
- NodeJS
- HTML
- CSS
- MySQL
- Redis
- Linux
那么我们如何存储Skill比较好呢(比较好包括:1. CRUD方便;2. 用的存储量小; )
二、使用Bit位
上述问题,我们因为Skill可以有一种或多种,我们可以用一串Bit来标识,比如Skill的数据类型为MySQL的无符号tinyint
,则含有8个Bit
我们从低位起,高位结束,会那项技能,就给那项置为1,其它位为0,则:
串 | 位置(从1开始) | 值 | 含义 |
---|---|---|---|
0000 0001 | 1 | 1 | 会Java |
0000 0010 | 2 | 2 | 会JavaScript |
0000 0100 | 3 | 4 | 会NodeJS |
0000 1000 | 4 | 8 | 会HTML |
0001 0000 | 5 | 16 | 会CSS |
0010 0000 | 6 | 32 | 会MySQL |
0100 0000 | 7 | 64 | 会Redis |
1000 0000 | 8 | 128 | 会Linux |
Bit操作都有那些:
- 按位与,符号为&
- 按位或,符号为|
- 按位取反,符号为~
- 异或,符号为xor
- 左移操作,符号为<<
- 右移操作.符号为>>
任意Bit位置0或置1,参考http://blog.csdn.net/xhfight/article/details/51537425
如果一个程序猿即会Java,又会JavaScript,那么这串Bit的第一位和第二位都为1,即0000 0011
,值为3
如果一个程序猿很牛逼,所有技能都会,那么这串bit为,1111 1111
,值为255
(可以把这个值想象成工资,会的越多,工资越高)
但是,值有了,我们如何确定一个程序猿是否会Java呢?
只要用 Skill & 1 === 1
则可以确定这个程序猿会Java
如果一个程序猿以前不会NodeJS,通过努力,学会了,则我们需要更新这位程序猿的Skill字段,把第三位也置为1,则可用Skill | 4
即可
如果一个程序猿学习能力特强,一次性地学会了NodeJS、MySQL、Radis,则我们更新这位程序猿的Skill字段,把第三、第六、第七位都要置为1,则用
Skill | 196
即可,那么这个196哪儿来的? 196 = 128 + 64 + 4
这些都是正常情况,如果一个程序猿年老色衰或太长时间没用某项技术,导致不会了,那么我们应该把代表这项技术的位置为0,比如这个程序猿不会Redis了,则Skill & ~(1 << (位置 - 1))
即可
三、MySQL的CRUD例子
SELECT * FROM rd WHERE skill & 1 = 1; -- 选出所有会Java的程序猿
SELECT * FROM rd WHERE skill & 16 = 16; -- 选出所有会CSS的程序猿
SELECT * FROM rd WHERE skill & 1 = 1 and skill & 16 = 16; -- 选出所有即会Java又会CSS的程序猿
UPDATE rd SET skill = skill | 1 WHERE id = 1; -- 把ID为1的这个程序猿的skill更新为会Java
UPDATE rd SET skill = skill | 16 WHERE id = 1; -- 把ID为1的这个程序猿的skill更新为会CSS
UPDATE rd SET skill = skill | 196 WHERE id = 1; -- 把ID为1的这个程序猿的skill更新为会NodeJS、MySQL、Redis
UPDATE rd SET skill = skill & ~(1<<6) WHERE id = 1; -- 把ID为1这个年老色衰的程序猿的skill更新为不会Redis