我们首先来看一个系统中常见的需求:

有一个广告表,我们要对广告做显示控制:

  • 手动上下线。

  • 只允许 VIP 查看。

可能的表结构如下:

  1. CREATE TABLE `finger_ad` (
  2. `ad_id` int() unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  3. `ad_name` varchar() NOT NULL COMMENT '广告名称',
  4. `ad_image_url` varchar() NOT NULL COMMENT '广告图片',
  5. `ad_url` varchar() NOT NULL COMMENT '广告图片URL跳转地址',
  6. `is_vip` tinyint() NOT NULL DEFAULT '' COMMENT '是否仅限 VIP 显示',
  7. `display` tinyint() NOT NULL DEFAULT '' COMMENT '显示状态:1显示、0隐藏',
  8. PRIMARY KEY (`ad_id`)
  9. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='广告表';

假如后期,我们需求更改了。需要再增加几种限制:

  • 已登录用户

  • 未登录用户

  • 30 天内未登录用户

  • 注册 30 天的用户

遇到这种限制条件的需求,开发同学是不是很伤脑筋?

可能很多开发第一反应就是在表结构增加这种新增的限制条件字段。一切看来似乎很美好。

的确,这样添加字段是最快最容易的方式。也能完成我们的需求。

但是,这样会引来如下毛病:

  • 每次增加限制条件。我们都要增加字段。这种对数据库的更动能少改就少改。毕竟,无限制的增加字段不可取。

  • 假如广告表数据量很大。大到增加一个字段需要几分钟的时候,这会给数据库服务器造成读写压力。

  • 条件越多,SQL 条件语句就会越来越长。

那么,还有没有更好的方式解决这些问题呢?

答案:有!

这就是我们今天要讲的按位与运算符的高级技巧。

我们把上面的表结构改一下:

  1. DROP TABLE IF EXISTS `finger_ad`;
  2. CREATE TABLE `finger_ad` (
  3. `ad_id` int() unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  4. `ad_name` varchar() NOT NULL COMMENT '广告名称',
  5. `ad_image_url` varchar() NOT NULL COMMENT '广告图片',
  6. `ad_url` varchar() NOT NULL COMMENT '广告图片URL跳转地址',
  7. `bit_condition` INT() UNSIGNED NOT NULL COMMENT '位运算条件:1-登录可访问、2-未登录可访问、4-30天注册可访问、8-30天未登录可访问、16-未消费可访问、32-VIP可访问',
  8. `display` tinyint() NOT NULL DEFAULT '' COMMENT '显示状态:1显示、0隐藏',
  9. PRIMARY KEY (`ad_id`)
  10. ) ENGINE=InnoDB DEFAULT CHARSET UTF8 COMMENT='广告表';

我们把所有的条件都去掉了。增加了一个字段: bit_condition 。把所有的条件都组合到一个字段。

那我们此时该如何写代码呢?

比如,现在要添加如下限制条件的广告:

只允许登录用户访问或已注册 30 天用户或是 VIP 用户才允许访问该广告。

那么,这个广告的 bit_condition 该如何设置值呢?很简单,把这几个条件的位值直接相加。此时值为:37。

很多可能会很奇怪。设置为 37 ,我怎么知道是这几个值的和呢?如果对 Linux 系统权限熟悉的同学就很容易理解这种做法。实际上,这里运用了按位与运算的特性:任意组合相加的值不会重复。

这个理解起来有一定难度。我三两句也很难给你梳理明白。大家可以在网上深入挖掘一下这方面儿的知识。你只需要知道这一点特点即可。

那么,现在我们该如何写 SQL 呢?

示例如下:

  1. SELECT * FROM finger_ad WHERE display = AND bit_condition & = bit_condition

这条 SQL 语句当中的 3 对应的是当前用户针对这么多条件得到的数值。如果 bit_condition位值是与 3 按位与与 bit_condition 结果相同,说明条件符合。

我们通过一个字段解决了所有条件的问题。着实得感谢按位与运算符的特性。同时也对 MySQL能支持位运算符感到开心。

那么,它有什么缺点呢?

想必有经验的同学已经看出来了。这种写法只能满足包含关系。假如要实现同时满足 3 个条件才能访问就不行了。或者,一个满足另外一个取反。

优点明显,同样缺点也很明显。大家要根据实际情况来选用。

扩展学习文件:

  1. <?php
  2. //例子1
  3. echo '<h2>demo1</h2><br>';
  4.  
  5. //定义常量
  6. define('D1',1);
  7. define('D2',2);
  8. define('D3',4);
  9. define('D4',8);
  10. define('D5',16);
  11.  
  12. function showStatus($state){
  13. for($i= 1;$i<=5;$i++){
  14. $d = 'D'.$i;
  15. $dd = constant($d); //取对应常量的值
  16. if(($state & $dd) > 0){
  17. echo '第'.$i.'盏灯亮'.'<br>'; //
  18. }else{
  19. echo '<span style="color: red">第'.$i.'盏灯灭</span>'.'<br>';
  20. }
  21. }
  22. echo "sql语句写法:SELECT * FROM `table` WHERE state & {$state} = state;";
  23. echo '<br>';
  24. echo '<br>';
  25. }
  26. $state = D4;
  27. showStatus($state); //只开第4盏灯
  28.  
  29. $state = D1;
  30. showStatus($state); //只开第1盏灯
  31.  
  32. $state = D4 | D1;
  33. showStatus($state); //开第1盏灯和第4盏灯
  34.  
  35. $state = (D4 | D2 | D1) & (~D1);
  36. showStatus($state); //开第1盏灯,第2盏灯和第4盏灯,然后关闭第1盏灯
  37. //例子2
  38. echo '<h2>demo2</h2><br>';
  39.  
  40. /**
  41. * 1、权限应用
  42. * 拥有哪些权限,就把这些权限对应的数值加起来
  43. * 例如:版主拥有权限(增加、删除、修改、查询),则版主的权限值存储为15(8+4+2+1)
  44. * 然后【权限值之和】 与 【实际权限值】做【位于】比较
  45. * 结果是真则拥有权限
  46. * 结果是假则没有权限
  47. *
  48. * 注意:权限值必须是2的N次方,从0次方开始,31次方是2147483648
  49. * 32次方是4294967296,已超过了常用int(10)最大存储4294967295,所以必须注意权限数量(<31个)
  50. * 当然如果存储格式为bitint或varchar等可以存储更长数字的格式,那么权限数量可以继续增加
  51. */
  52. // 赋予权限值-->删除:8、上传:4、写入:2、只读:1
  53. define('mDELETE',8);
  54. define('mUPLOAD',4);
  55. define('mWRITE',2);
  56. define('mREAD',1);
  57. //vvvvvvvvvvvvv使用说明vvvvvvvvvvvvv
  58. //部门经理的权限为(假设它拥有此部门的所有权限),| 是位或运行符,不熟悉的就查查资料
  59. echo '全部权限为:'.(mDELETE|mUPLOAD|mWRITE|mREAD).'<br>';// 相当于是把上面的权限值加起来:8+4+2+1=15
  60.  
  61. /*
  62. *赋予它多个权限就分别取得权限值相加,又比如某位员工拥有除了删除外的权限其余都拥有,那它的权限值是多少?
  63. *应该是:4+2+1=7
  64. */
  65.  
  66. //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  67. //判断某人的权限可用,设权限值在$key中
  68. /*
  69. *判断权限用&位与符,
  70. */
  71. // 设我只有 upload 和 read 权限,则
  72. $key = (mUPLOAD|mREAD);//相当于是把上传、只读的权限值分别相加:4+1=5
  73. echo '当前权限为:'.$key.'<br>';;
  74. if($key & mDELETE){
  75. echo '有删除权限'.'<br>'; //
  76. }else{
  77. echo '<span style="color: red">无删除权限</span>'.'<br>'; //
  78. }
  79. if($key & mUPLOAD){
  80. echo '有上传权限'.'<br>'; //
  81. } else{
  82. echo '<span style="color: red">无上传权限</span>'.'<br>'; //
  83. }
  84. if($key & mWRITE){
  85. echo '有写入权限'.'<br>'; //
  86. } else{
  87. echo '<span style="color: red">无写入权限</span>'.'<br>'; //
  88. }
  89. if($key & mREAD){
  90. echo '有只读权限'.'<br>'; //
  91. } else{
  92. echo '<span style="color: red">无只读权限</span>'.'<br>'; //
  93. }
  94. ?>

运行结果:

位运算在 PHP 实际项目当中的高级运用的更多相关文章

  1. EF架构~为分组添加位运算聚合方法

    回到目录 我们知道在Linq里的分组groupby可以对集合中一个或者多个字段进行分组,并对其中一个属性进行聚合,而Linq为我们提供了多种聚合方法,由aver,sum,count等,而在大叔权限体系 ...

  2. 深入理解计算机系统(2.2)---布尔代数以及C语言上的位运算

    布尔代数上的位运算 布尔代数是一个数学知识体系,它在0和1的二进制值上演化而来的. 我们不需要去彻底的了解这个知识体系,但是里面定义了几种二进制的运算,却是我们在平时的编程过程当中也会遇到的.这四种运 ...

  3. C语言回顾-函数和位运算

    1.函数的概述 功能独立的代码块 C语言由若干函数组成 1)从定义分,库函数和用户定义函数两种 2)从返回值分,有返回值函数和无返回值函数 3)从参数分,无参函数和有参函数 2.形参和实参 1)形参定 ...

  4. 神奇的Noip模拟试题 T3 科技节 位运算

    3 科技节 (scifest.pas/.c/.cpp) [问题描述] 一年一度的科技节即将到来.同学们报名各项活动的名单交到了方克顺校长那,结果校长一看皱了眉头:这帮学生热情竟然如此高涨,每个人都报那 ...

  5. 《分销系统-原创第一章》之“多用户角色权限访问模块问题”的解决思路( 位运算 + ActionFilterAttribute )

    此项目需求就是根据给用户分配的权限,进行相应的权限模块浏览功能,因为项目不是很大,所以权限没有去用一张表去存,我的解决思路如下,希望大家给点建议. 数据库用户表结构如下: 数据库表梳理: BankUs ...

  6. 关于C/C++中的位运算技巧

    本篇文章讲述在学习CSAPP位运算LAB时的一些心得. 移位运算的小技巧 C/C++对于移位运算具有不同的策略,对于无符号数,左右移位为逻辑移位,也就是直接移位:对于有符号数,采用算术移位的方式,即左 ...

  7. Apriori算法-位运算-C语言

    原文地址:http://blog.csdn.net/liema2000/article/details/6118423 //////////////////////////////////////// ...

  8. C#中缓存的使用 ajax请求基于restFul的WebApi(post、get、delete、put) 让 .NET 更方便的导入导出 Excel .net core api +swagger(一个简单的入门demo 使用codefirst+mysql) C# 位运算详解 c# 交错数组 c# 数组协变 C# 添加Excel表单控件(Form Controls) C#串口通信程序

    C#中缓存的使用   缓存的概念及优缺点在这里就不多做介绍,主要介绍一下使用的方法. 1.在ASP.NET中页面缓存的使用方法简单,只需要在aspx页的顶部加上一句声明即可:  <%@ Outp ...

  9. 136.Single Number---异或、位运算

    题目链接 题目大意:给出一串数组,里面的数都是两个,只有一个数是一个,把这个只有一个的数找出来.时间复杂度最好是线性的,空间复杂度最好为O(1). 法一:利用map,空间换时间,代码如下(耗时26ms ...

随机推荐

  1. Linux命令——whiptail交互式shell脚本对话框

    转自:交互式shell脚本对话框----whiptail指令 当你在linux环境下setup软件的时候就会有相应的对话框让你输入.虽然我们已经习惯了这种交互的方法,但是如果有一种直观的界面来输入是不 ...

  2. Linux标准IO和管道

    Linux标准IO和管道 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.标准输入和输出 程序:指令+数据 读入数据:Input 输出数据:Output 打开的文件都有一个fd: ...

  3. springboot 2.x整合redis,spring aop实现接口缓存

    pox.xml: <dependency> <groupId>org.springframework.boot</groupId> <artifactId&g ...

  4. java基础(14)---修饰符

    修饰符:final .static.public.protected.private.default. 一.final(不能修改) 使用final修饰变量定义:该变量一旦被初始化之后就不允许再被修改. ...

  5. 鸡尾酒排序Cocktail Sort (双向冒泡排序)

    鸡尾酒排序 鸡尾酒排序思路,先从左边开始进行冒泡排序,第一趟冒泡排序完,最大值在的数组的最右端,然后进行第二趟排序,第二趟排序从右边开始排序,第二趟结束时,最小值在数组最左端,以此类推,每一趟排序完都 ...

  6. Docker创建mysql镜像

    原文: https://blog.csdn.net/uk8692/article/details/49386679 https://blog.csdn.net/qq362228416/article/ ...

  7. 使用Zookeeper实现负载均衡原理

    思路 使用Zookeeper实现负载均衡原理,服务器端将启动的服务注册到,zk注册中心上,采用临时节点.客户端从zk节点上获取最新服务节点信息,本地使用负载均衡算法,随机分配服务器. 创建项目工程 M ...

  8. 使用postman开发testcases记录贴

    我使用了两个版本的postman: Postman-linux-x64-7.1.1 这是目前(2019)最新版本.这个版本也有坑: (因为系统崩溃重装了,所以目前只有最新版本.本文截图都是这个版本的截 ...

  9. 1129. Shortest Path with Alternating Colors

    原题链接在这里:https://leetcode.com/problems/shortest-path-with-alternating-colors/ 题目: Consider a directed ...

  10. 洛谷 UVA12101 Prime Path 题解

    一道经典的BFS 用四个for搜索四位就行了,只要能推出怎么只变4位中的一位就很水了 #include<iostream> #include<cstring> #include ...