咱們首先來看一個系統中常見的需求:php
有一個廣告表,咱們要對廣告作顯示控制:laravel
可能的表結構以下:sql
CREATE TABLE `finger_ad` ( `ad_id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵', `ad_name` varchar(50) NOT NULL COMMENT '廣告名稱', `ad_image_url` varchar(255) NOT NULL COMMENT '廣告圖片', `ad_url` varchar(255) NOT NULL COMMENT '廣告圖片URL跳轉地址', `is_vip` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否僅限 VIP 顯示', `display` tinyint(1) NOT NULL DEFAULT '1' COMMENT '顯示狀態:1顯示、0隱藏', PRIMARY KEY (`ad_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='廣告表';
假如後期,咱們需求更改了。須要再增長几種限制:shell
遇到這種限制條件的需求,開發同窗是否是很傷腦筋?數據庫
可能不少開發第一反應就是在表結構增長這種新增的限制條件字段。一切看來彷佛很美好。服務器
的確,這樣添加字段是最快最容易的方式。也能完成咱們的需求。架構
可是,這樣會引來以下毛病:併發
那麼,還有沒有更好的方式解決這些問題呢?分佈式
答案:有!微服務
這就是咱們今天要講的按位與運算符的高級技巧。
咱們把上面的表結構改一下:
DROP TABLE IF EXISTS `finger_ad`; CREATE TABLE `finger_ad` ( `ad_id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵', `ad_name` varchar(50) NOT NULL COMMENT '廣告名稱', `ad_image_url` varchar(255) NOT NULL COMMENT '廣告圖片', `ad_url` varchar(255) NOT NULL COMMENT '廣告圖片URL跳轉地址', `bit_condition` INT(11) UNSIGNED NOT NULL COMMENT '位運算條件:1-登陸可訪問、2-未登陸可訪問、4-30天註冊可訪問、8-30天未登陸可訪問、16-未消費可訪問、32-VIP可訪問', `display` tinyint(1) NOT NULL DEFAULT '1' COMMENT '顯示狀態:1顯示、0隱藏', PRIMARY KEY (`ad_id`) ) ENGINE=InnoDB DEFAULT CHARSET UTF8 COMMENT='廣告表';
咱們把全部的條件都去掉了。增長了一個字段:bit_condition
。把全部的條件都組合到一個字段。
那咱們此時該如何寫代碼呢?
好比,如今要添加以下限制條件的廣告:
只容許登陸用戶訪問或已註冊 30 天用戶或是 VIP 用戶才容許訪問該廣告。
那麼,這個廣告的bit_condition
該如何設置值呢?很簡單,把這幾個條件的位值直接相加。此時值爲:37。
不少可能會很奇怪。設置爲 37 ,我怎麼知道是這幾個值的和呢?若是對 Linux 系統權限熟悉的同窗就很容易理解這種作法。實際上,這裏運用了按位與運算的特性:任意組合相加的值不會重複。
這個理解起來有必定難度。我三兩句也很難給你梳理明白。你們能夠在網上深刻挖掘一下這方面兒的知識。你只須要知道這一點特色便可。
那麼,如今咱們該如何寫 SQL 呢?
示例以下:
SELECT * FROM finger_ad WHERE display = 1 AND bit_condition & 3 = bit_condition
這條 SQL 語句當中的 3 對應的是當前用戶針對這麼多條件獲得的數值。若是bit_condition
位值是與 3 按位與與bit_condition
結果相同,說明條件符合。
咱們經過一個字段解決了全部條件的問題。着實得感謝按位與運算符的特性。同時也對MySQL
能支持位運算符感到開心。
那麼,它有什麼缺點呢?
想必有經驗的同窗已經看出來了。這種寫法只能知足包含關係。假如要實現同時知足 3 個條件才能訪問就不行了。或者,一個知足另一個取反。
優勢明顯,一樣缺點也很明顯。你們要根據實際狀況來選用。
擴展學習文件:
<?php //例子1 echo '<h2>demo1</h2><br>'; //定義常量 define('D1',1); define('D2',2); define('D3',4); define('D4',8); define('D5',16); function showStatus($state){ for($i= 1;$i<=5;$i++){ $d = 'D'.$i; $dd = constant($d); //取對應常量的值 if(($state & $dd) > 0){ echo '第'.$i.'盞燈亮'.'<br>'; //8 }else{ echo '<span >第'.$i.'盞燈滅</span>'.'<br>'; } } echo "sql語句寫法:SELECT * FROM `table` WHERE state & {$state} = state;"; echo '<br>'; echo '<br>'; } $state = D4; showStatus($state); //只開第4盞燈 $state = D1; showStatus($state); //只開第1盞燈 $state = D4 | D1; showStatus($state); //開第1盞燈和第4盞燈 $state = (D4 | D2 | D1) & (~D1); showStatus($state); //開第1盞燈,第2盞燈和第4盞燈,而後關閉第1盞燈 //例子2 echo '<h2>demo2</h2><br>'; /** * 一、權限應用 * 擁有哪些權限,就把這些權限對應的數值加起來 * 例如:版主擁有權限(增長、刪除、修改、查詢),則版主的權限值存儲爲15(8+4+2+1) * 而後【權限值之和】 與 【實際權限值】作【位於】比較 * 結果是真則擁有權限 * 結果是假則沒有權限 * * 注意:權限值必須是2的N次方,從0次方開始,31次方是2147483648 * 32次方是4294967296,已超過了經常使用int(10)最大存儲4294967295,因此必須注意權限數量(<31個) * 固然若是存儲格式爲bitint或varchar等能夠存儲更長數字的格式,那麼權限數量能夠繼續增長 */ // 賦予權限值-->刪除:八、上傳:四、寫入:二、只讀:1 define('mDELETE',8); define('mUPLOAD',4); define('mWRITE',2); define('mREAD',1); //vvvvvvvvvvvvv使用說明vvvvvvvvvvvvv //部門經理的權限爲(假設它擁有此部門的全部權限),| 是位或運行符,不熟悉的就查查資料 echo '所有權限爲:'.(mDELETE|mUPLOAD|mWRITE|mREAD).'<br>';// 至關因而把上面的權限值加起來:8+4+2+1=15 /* *賦予它多個權限就分別取得權限值相加,又好比某位員工擁有除了刪除外的權限其他都擁有,那它的權限值是多少? *應該是:4+2+1=7 */ //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //判斷某人的權限可用,設權限值在$key中 /* *判斷權限用&位與符, */ // 設我只有 upload 和 read 權限,則 $key = (mUPLOAD|mREAD);//至關因而把上傳、只讀的權限值分別相加:4+1=5 echo '當前權限爲:'.$key.'<br>';; if($key & mDELETE){ echo '有刪除權限'.'<br>'; //8 }else{ echo '<span >無刪除權限</span>'.'<br>'; //8 } if($key & mUPLOAD){ echo '有上傳權限'.'<br>'; //4 } else{ echo '<span >無上傳權限</span>'.'<br>'; //4 } if($key & mWRITE){ echo '有寫入權限'.'<br>'; //2 } else{ echo '<span >無寫入權限</span>'.'<br>'; //2 } if($key & mREAD){ echo '有隻讀權限'.'<br>'; //1 } else{ echo '<span >無只讀權限</span>'.'<br>'; //1 } ?>
運行結果:
以上內容但願幫助到你們,不少PHPer在進階的時候總會遇到一些問題和瓶頸,業務代碼寫多了沒有方向感,不知道該從那裏入手去提高,對此我整理了一些資料,包括但不限於:分佈式架構、高可擴展、高性能、高併發、服務器性能調優、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql優化、shell腳本、Docker、微服務、Nginx等多個知識點高級進階乾貨須要的能夠免費分享給你們,須要點擊這裏