[关闭]
@dume2007 2017-03-21T08:12:42.000000Z 字数 1667 阅读 1352

数据库状态标识位flag设计

mysql flag


设计目的

运用场景

例子1:管理用户的支付方式

比如针对不同用户组设置了不同的支付方式支持,假设支付方式有支付宝微信银联借条等。A用户支持支付宝、微信;B用户支持支付宝、微信、借条。一般用户支付方式数据库设计为:

ID name alipay weixin union iou
1 A 1 1 0 0
2 B 1 1 0 1

这时如果后续多了其它支付方式后,就需要调整表结构增加字段,如快钱、货到付款等。这种设计方式明显不符合数据库设计第一范式,增加了很多冗余字段和存储空间。

例子2:设置用户的操作权限

比如有一组权限列表,查看编辑发布删除,数据库可能会是这样:

ID name is_visible is_editble is_publishable is_deleteable
1 A 1 1 0 0
2 B 1 1 1 1

上面只是举些例子来说明一个问题,当一张表的字段里包含很多这些状态值01时,我们可以使用二进制的方式来表示,而且只需要一个字段就好了。

设计思路

比如例1中的支付方式,假设我们最多可设计有10种支付方式。

此处输入图片的描述

字段仍设为int整形,A支持支付宝、微信,则值为12(0000001100);B支持支付宝、微信、借条,则值为13(0000001101),表结构如下:

ID name pay_flag
1 A 12
2 B 13

如果增加了货到付款,可再赋值给二进制的第五位,其它位还是保持不变。

这时候会涉及到数据库查询问题,比如上面的值12、13都支持支付宝、微信,还有14(0000001110)、15(0000001111)也支持,如果增加了二进制第五位,那么会有更多匹配值,如30(0000011110)、28(0000011100)等...
如果要查询支持支付宝、微信的数据怎么办?这时只需要通过“位”的与运算,就能简单的查询出想要数据:

  1. select * from user_pay where pay_flag & b'0000001100';
  2. # 或者:
  3. select * from user_pay where pay_flag & 12;

php简单实现

  1. class PayFlag {
  2. const ALIPAY = 8; //01000
  3. const WEIXIN = 4; //00100
  4. const UNION = 2; //00010
  5. const IOU = 1; //00001
  6. function addFlag($old_flag, $flag) {
  7. return $old_flag | $flag;
  8. }
  9. function delFlag($old_flag, $flag) {
  10. return $old_flag ^ $flag;
  11. }
  12. }
  13. $old_flag = 6; //00110
  14. $PayFlag = new PayFlag;
  15. //原有值 - 输出 6:110
  16. echo($old_flag . ":" . decbin($old_flag) . PHP_EOL);
  17. //增加ALIPAY - 输出 14:1110
  18. $new_flag = $PayFlag->addFlag($old_flag, PayFlag::ALIPAY);
  19. echo($new_flag . ":" . decbin($new_flag) . PHP_EOL);
  20. //移除ALIPAY - 输出 6:110
  21. $new_flag = $PayFlag->delFlag($new_flag, PayFlag::ALIPAY);
  22. echo($new_flag . ":" . decbin($new_flag) . PHP_EOL);
  23. //移除UNION - 输出 4:100
  24. $new_flag = $PayFlag->delFlag($new_flag, PayFlag::UNION);
  25. echo($new_flag . ":" . decbin($new_flag) . PHP_EOL);
  26. //增加IOU - 输出 5:101
  27. $new_flag = $PayFlag->delFlag($new_flag, PayFlag::IOU);
  28. echo($new_flag . ":" . decbin($new_flag) . PHP_EOL);
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注