目錄php
視圖是MySQL在5.0.1版本中加入的功能.它能夠理解爲一個虛表.mysql
之因此被稱爲虛表,是由於它只是存儲了一個結構,並不存儲真實的數據.
行和列的數據來自定義視圖的查詢中使用的表,而且是在使用視圖時動態生成
的,只保存了sql邏輯,不保存查詢結果.程序員
視圖並非真的優化web
--建立視圖的語法:sql
create view 視圖名稱 as select語句;
--建立一個視圖數據庫
create view user_view as select id,name,age,sex from user;
查看視圖的方式和表同樣能夠經過select來查看,desc查看視圖結構編程
注意:視圖查詢的數據實則來自於源數據中的內容.而它本質只是存儲了一個結構,並非存儲真實的數據緩存
好比:PHP當中封裝了一個查詢的方法安全
1. 第一個顯著優勢就是它簡化了操做. 此時咱們徹底不用關心視圖是怎麼處理數據的, 咱們只須要知道如何使用這個結果集便可,視圖至關於一箇中間層. 2. 第二個顯著優勢就是它更加安全. 好比咱們可讓用戶有權去訪問某個視圖,可是不能訪問原表, 這樣就能夠起到保護原表中某些數據的做用. 3. 咱們以後會接觸到管理權限,權限是沒法細緻到某一個列的,經過視圖,則很容易實現. 4. 第三個顯著優勢就是下降耦合.假如咱們之後要修改原表的結構,那麼咱們能夠經過修改視圖的定義便可, 而不用修改應用程序,對訪問者是不會形成影響 的,通常來講,這樣代價會更小.
1. 性能:從數據庫視圖查詢數據可能會很慢,特別是若是視圖是基於其餘視圖建立的. 2. 表依賴關係:將根據數據庫的基礎表建立一個視圖.每當更改與其相關聯的表的結構時,都必須更改視圖.
表的數據是能夠修改與更新的,可是在視圖就不必定了.服務器
--修改視圖字段的值會直接修改到源數據表 update `user_view` set name='小哈' where id=1; select * from `user`; --刪除視圖 drop view user_view;
1. 包含聚合函數、distinct、group by、having、union、union all. 2. 常量視圖. 3. select 包含子查詢. 4. 包含鏈接操做. 5. from 一個不能更新的視圖. 6. where 子句的子查詢引用了 from 子句中的表.
建立一個視圖:
create view user_view_2 as select id,name,age,sex,status from `user` where status=0; select * from `user_view_2`;
如今給視圖添加一條status=1的數據
insert into `user_view_2`(id,name,age,sex,status)values(11,'小每天',22,'男',1); select * from `user_view_2`; select * from `user`;
能夠發現即便不知足視圖的條件也能夠插入數據到表裏面
with check option
1. 對於上面的表 t2,咱們想:是否能夠建立一個視圖,它只容許修改知足本視圖要求的數據, 而對於不知足本視圖要求的數據操做, 通通拒絕呢? 2. 答案是確定的.那就須要 with check option 了,不過該修飾符還有更加深一步的權限機制. 3. 首先咱們仍是利用上一步的 t2,咱們建立一個視圖 v3,它的建立
drop view `user_view_2`; create view user_view_3 as select id,name,age,sex,status from `user` where status=0 with check option; insert into `user_view_3`(id,name,age,sex,status)values(12,'小灰灰',22,'男',1); select * from `user_view_3`;
錯誤信息
[Err] 1369 - CHECK OPTION failed 'mysql_php.user_view_3'
這裏能夠理解爲 with check option 的做用就是多了一個 check 的功能,即檢查的功能,
也就是說插入的數據必須知足該視圖的條件,才容許被操做
1.提升了重用性,就像一個函數.若是要頻繁獲取user的name和goods的name.就應該使用如下sql語言.
示例:
select a.name as username, b.name as goodsname from user as a, goods as b, ug as c where a.id=c.userid and c.goodsid=b.id;
但有了視圖就不同了,建立視圖other.
示例
create view other as select a.name as username, b.name as goodsname from user as a, goods as b, ug as c where a.id=c.userid and c.goodsid=b.id;
建立好視圖後,就能夠這樣獲取user的name和goods的name.
示例
select * from other;
以上sql語句,就能獲取user的name和goods的name了.
2.對數據庫重構,卻不影響程序的運行.假如由於某種需求,須要將user拆房表usera和表userb,該兩張表的結構以下:
測試表:usera有id,name,age字段 測試表:userb有id,name,sex字段
這時若是php端使用sql語句:
select * from user;
那就會提示該表不存在,這時該如何解決呢.解決方案:建立視圖.如下sql語句建立視圖:
create view user as select a.name,a.age,b.sex from usera as a, userb as b where a.name=b.name;
以上假設name都是惟一的.
此時php端使用sql語句:
select * from user;
就不會報錯什麼的.
這就實現了更改數據庫結構,不更改腳本程序的功能 .
3.提升了安全性能.能夠對不一樣的用戶,設定不一樣的視圖.
例如:某用戶只能獲取user表的name和age數據,不能獲取sex數據.
則能夠這樣建立視圖.示例以下:
create view other as select a.name, a.age from user as a;
這樣的話,使用sql語句:
select * from other;
最多就只能獲取name和age的數據,其餘的數據就獲取不了了.
1. 觸發器(trigger)是MySQL提供給程序員和數據分析員來保證數據完整性的一種方法. 2. 它是與表事件相關的特殊的存儲過程,它的執行不是由程序調用,也不是手工啓動, 而是由事件來觸發,好比當對一個表進行操做(insert,delete, update)時就會激活它執行.
--觸發器建立語法
create trigger [觸發器名稱] trigger_time trigger_event on [表名] for each row begin trigger_stmt end;
trigger_time:指的是觸發器的觸發時間,能夠是 before 或者是 after.其中 before 表示在檢查約束前觸發,而 after 表示在檢查約束後觸發.
trigger_event: 是觸發器的觸發事件,能夠是 insert、update、delete.
trigger_stmt:觸發事件執行的語句
對同一個表相同觸發時間、相同觸發事件的狀況下,只能定義一個觸發器.
其中的 for each row 表示是行級觸發的,也就是以行爲單位.也有數據庫支持語句級觸發.可是目前對於 MySQL 來講 for each row 幾乎是必須只能這麼 寫.
定義一個觸發器
--建立一個觸發器,用於監視`user`表,只要`user`表新增數據,`test`表同樣增長一條數據 create trigger user_trigger after insert on `user` begin for each row insert into `test` (id,name,age,sex,status)values(3,'小哈',22,'男',1); end --向`user`表添加一條id=12的數據 insert into `user` (id,name,age,sex,status)values(12,'小哈哈',33,'男',1); --查詢`test`表與`user`表的內容 select * from `test`; select * from `user`;
這時觸發器的做用就已經體現出來了,在咱們向user中插入數據的時候, test中的數據也會自動隨着變化.
若是咱們要查看已經建立的觸發器,能夠選定某個數據庫
--查看選定數據庫的觸發器 show triggers \G;
1. MySQL觸發器能基於行觸發,MySQL觸發器始終時基於表中的一條記錄觸發,而不是一組SQL語句. 所以,若是須要變更整個數據集而數據集數據量又較大 時,觸發器效果會很是低. 2. 每個表的一個事件只能定義一個觸發器,例如:不能在AFTER INSERT上定義一個以上的觸發器.
產因爲MySQL觸發器基於行觸發的特性,所以對於批量操做並不適合使用觸發器,如:彙總表、緩存表等.
觸發器使用不當,可能會致使如下問題:
1. 一個MySQL觸發器可能會關聯到另一張表或幾張表的操做. 所以,會致使數據庫服務器負荷也會相應的增長一倍或幾倍,若是出現由於觸發器問題致使的性能問題, 會很難定位問題位置和緣由. 2. 在基於鎖的操做中,觸發器可能會致使鎖等待或死鎖.觸發器執行失敗,原來執行的SQL語名也會執行失敗. 而由於觸發器致使的失敗結果和失敗緣由,往 往很難排查.
因爲MySQL觸發器的種種問題,要求咱們在建立觸發器就應該充分考慮.
避免使用不合適的觸發器,並能對全部觸發器有足夠的瞭解,以便問題的定位和排查.
觸對MySQL觸發器有足夠的認識和了解後,MySQL觸發器會給咱們帶來極大的便利.
當實現一些系統約束時,或在實現系統維護及針對操做數據的更新時,使用 觸發器都很是方便.
在之膠咱們介紹了MySQL觸發器不適合作的一些工做,但MySQL觸發器在如下一些應用場景中,會很是實用:
1. 基於行數據變動的日誌記錄. 如:在用戶訂單系統中,咱們能夠基於用戶訂單數據狀態的改變,使用觸發器構建用戶訂單日誌表數據. 2. 基於行數據變動的關係數據的更新. 如:用戶訂單改變至付款或相關狀態時,咱們能夠基於用戶訂單數據狀態的改變,使用觸發器改變用戶會付款或相應狀態信息. 3. 基於行數據變動的數據彙總. 如:用戶訂單成交或失敗,咱們能夠基於用戶訂單數據狀態的改變,使用觸發器構建用戶總成交量或失敗量彙總數據.
1. MySQL 從 5.0 開始支持存儲過程. 2. 存儲過程和函數能夠理解爲一段 SQL 語句的集合,它們被事先編譯好而且存儲在數據庫中. 3. 在 Pascal 語言中,是有」過程」和」函數」的區分的,過程能夠理解爲沒有返回值的函數. 不過在 C 家族語言中,則沒有過程這個概念,統一爲函數.
--存儲過程建立語法 create procedure 存儲過程名(參數列表) begin 存儲過程體 end
當咱們調用一個存儲過程的時候,可使用以下方式:
--調用存儲過程的方式 call 存儲過程名(參數列表)
下面建立一個簡單的存儲過程:
--建立一個存儲過程,用於建立t1表 create procedure user_procedure() begin create table t1(id int,name varchar(25)); end --調用存儲過程user_procedure call user_procedure(); --建立一個能向t1表新增數據的存儲過程 create procedure user_insert_procedure(in x int,in y varchar(25))--in 表示輸入 begin insert into t1 values(x,y); end --調用存儲過程user_insert_procedure call user_insert_procedure(1,'sixstar');
參數類型
1. 從上面的過程當中咱們瞭解到存儲過程有參數類型這種說法,它的類型能夠取值有三個:in、out、inout. 2. 其中它們的意義以下: (1)in 表示只是用來輸入. (2)out 表示只是用來輸出. (3)inout 能夠用來輸入,也能夠用做輸出.
--建立一個擁有輸入與輸出變量的存儲過程 create procedure user_procedure_out(in x int,out y varchar(25)) begin select `name` into y from `t1` where id=x; end --調用存儲過程user_procedure_out call user_procedure_out(1,@a); --查詢輸出結果 select @a;
刪除存儲過程
--刪除存儲過程語法 drop procedure 存儲過程名 drop procedure user_procedure;
1. 調用存儲過程與直接執行 SQL 語句的效果是相同的,可是存儲過程的一個好處是處理邏輯都封裝在數據庫端. 2. 當咱們調用存儲過程的時候,咱們不須要了解其中的處理邏輯,一旦處理邏輯發生變化,只須要修改存儲過程便可, 對調用它的程序徹底無影響. 3. 調用存儲過程和函數能夠簡化應用開發人員的不少工做,減小數據在數據庫和應用服務器之間的傳輸, 能夠提升數據處理的效率.
存儲過程當中是可使用變量的,咱們能夠經過 declare 來定義一個局部變量,
該變量的做用域只是 begin....end 塊中.
變量的定義必須寫在符合語句的開頭,而且在任何其餘語句的前面.咱們能夠一次聲明多個相同類型的變量,
咱們還可使用default 來賦予默認值.
定義一個變量的語法爲:
declare 變量名 1 [,變量名 2...] 變量類型 [default 默認值]
上面的變量類型就是 MySQL 支持的類型,而變量名的取值規則也是一個老生常談的話題了,就不贅述了.
變量能夠直接賦值,還能夠經過查詢賦值.
直接賦值就是使用 set 來進行賦值,它的語法爲:
set 變量名 1 = 表達式 1 [,變量名 2=表達式 2...]
7.也能夠經過查詢來將結果賦值給變量,它須要要求查詢返回的結果只有一行,語法範例:
select 列名列表 into 變量列表 from 表名 其餘語句;
8.定義一個存儲過程,練習變量使用
create procedure user_procedure_declare(in x int,out y varchar(25)) begin declare s varchar(25); select `name` into s from `t1` where id=x; set y=s; end call user_procedure_declare(1,@a); select @a;
存儲過程當中的數據類型
1. 數值類型:Int,float,double,decimal 2. 日期類型:timestamp,date,year 3. 字符串:char,varchar,text
timestamp: 是使用最多的數據類型-》十位數的時間戳 text:一旦用到text類型的時候就能夠考慮分表;
若是部分表的話,該字段的查詢不會直接放在一塊兒查詢,由於多個字段查詢中其中若是有text字段的話,
就容易遇到慢查詢因此一般的話,若是須要這個值的時候會根據id單獨拿這個text字段
if 的語法格式爲: if 條件表達式 then 語句 [elseif 條件表達式 then 語句] .... [else 語句] end if case 的語法格式 首先是第一種寫法: case 表達式 when 值 then 語句 when 值 then 語句 ... [else 語句] end case 而後是第二種寫法: case when 表達式 then 語句 when 表達式 then 語句 .... [else 語句] end case loop 循環語法格式爲: [標號:] loop 循環語句 end loop [標號] while while a>100 do 循環語句 End while Repeat //遊標 SQL語句1 UNTIL 條件表達式 END Repeat; Loop SQL語句 全部的條件判斷和跳出須要本身實現 End loop leave語句用來從標註的流程構造中退出,它一般和begin...end或循環一塊兒使用leave標號; 聲明語句結束符,能夠自定義: DELIMITER [符合] delimiter $$ $$
1. 遊標也有的資料上稱爲光標. 2. 咱們能夠在存儲過程當中使用遊標來對結果集進行循環的處理. 3. 遊標的使用步驟基本分爲:聲明、打開、取值、關閉.
DECLARE test_cursor CURSOR FOR 結果集; //聲明遊標 OPEN test_cursor; //打開遊標 CLOSE test_cursor; //關閉遊標 DECLARE CONTINUE HANDLER FOR NOT FOUND //結果集查詢不到數據自動跳出
1. 遊標的聲明的語法:declare 遊標名稱 cursor for 查詢語句; 2. 打開光標的語法:open 遊標名稱; 3. 獲取遊標數據:fetch 遊標名稱 into 變量名 1 [,變量名 2 ....] 4. 關閉遊標的語法:close 遊標名稱; 5. 遊標的基本使用須知:對某個表按照循環的處理,判斷循環結束的條件是捕獲not found的條件, 當 fetch 光標找不到下一條記錄的時候,就會關閉光標然 後退出過程. 6. 可能有過 Pascal 編程經驗的朋友們都會知道,聲明的順序也是很重要的,在SQL中, 咱們使用 declare 定義的順序是:變量、條件、遊標、應用程序.
操做查詢出來的數據會放置於臨時表中,而後再經過遊標去讀取數據.
1. 第一點優點就是執行速度快.由於咱們的每一個SQL語句都須要通過編譯, 而後再運行,可是存儲過程都是直接編譯好了以後,直接運行便可. 2. 第二點優點就是減小網絡流量.咱們傳輸一個存儲過程比咱們傳輸大量的 SQL 語句的開銷要小得多. 3. 第三點優點就是提升系統安全性.由於存儲過程可使用權限控制, 並且參數化的存儲過程能夠有效地防止SQL注入***.保證了其安全性. 4. 第四點優點就是耦合性下降.當咱們的表結構發生了調整或變更以後,咱們能夠修改相應的存儲過程, 咱們的應用程序在必定程度上須要改動的地方就較小了. 5. 第五點優點就是重用性強.由於咱們寫好一個存儲過程以後,再次調用它只須要一個名稱便可, 也就是」一次編寫,隨處調用」,並且使用存儲過程也可讓程 序的模塊化增強.
1. 第一個缺點就是移植性差.由於存儲過程是和數據庫綁定的,若是咱們要更換數據庫之類的操做,可能不少地方須要改動. 2. 第二個缺點就是修改不方便. 由於對於存儲過程而言,咱們並不能特別有效的調試, 它的一些bug可能發現的更晚一些,增長了應用的危險性. 3. 第三個缺點就是優點不明顯和贅餘功能.對於小型web應用來講,若是咱們使用語句緩存,發現編譯SQL的開銷並不大, 可是使用存儲過程卻須要檢查權限一類的開銷,這些贅餘功能也會在 必定程度上拖累性能.
1. 存儲過程和函數的優點是能夠將數據的處理放在數據庫服務器上進行, 避免將大量的結果集傳輸給客戶端,減小了數據的傳輸,所以也減小了寬帶和服務器的壓力. 2. 可是在數據庫服務器上進行大量的運算也會佔用服務器的 CPU,形成數據庫服務器的壓力. 3. 通常來講是不建議在存儲過程當中進行大量的複雜的運算的,它們不是數據庫服務器的強項, 咱們應該把這些操做讓應用服務器去處理.