1. 程式人生 > >2018.11.26檢視,觸發器.事物.儲存過程.函式.資料備份與恢復.流程控制

2018.11.26檢視,觸發器.事物.儲存過程.函式.資料備份與恢復.流程控制

2018.11.26

一檢視

1什麼是檢視

檢視是有一張表或多張表的查詢結果構成的一張虛擬表,本質儲存一個 sql 語句在data檔案裡,當你呼叫它的時候就會執行這段sql語句.如果對檢視的記錄內容進行修改原本的資料記錄也會被修改,反之亦然.

 

2為什麼使用檢視

 

當我們在使用多表查詢時 我們的sql語句可能會非常的複雜,如果每次都編寫一遍sql'的話無疑是一件麻煩的事情,這時候就可以使用檢視來避免多次編寫sql的問題;

簡答的說可以幫我們節省sql的編寫,

檢視的另一個作用是,可以不同的檢視來展示開放不同資料的訪問(可以限制給使用者觀看的資料條數,縱列)

 

CREATE [OR REPLACE] VIEW view_name [(column_list)]

AS select_statement

create or replace view stu(name,class) as select student.name,stu_info.class

from student,stu_info where student.s_id = stu_info.s_id ;

 

 

加上OR REPLACE 時如果已經存在相同檢視則替換原有檢視

column_list指定哪些欄位要出現在檢視中

注意:由於是一張虛擬表,檢視中的資料實際上來源於其他其他表,所以在檢視中的資料不會出現在硬碟上

 

使用檢視

檢視是一張虛擬表 所以使用方式與普通表沒有任何區別

 

檢視檢視

 

1.desc view_name; //檢視資料結構

2.show create view view_name;//檢視 建立語句

 

修改檢視

alter view_name select_statement

alter view stu(s_id,name,class) as select student.s_id,student.name,stu_info.class

from student,stu_info where student.s_id = stu_info.s_id ;

 

update view_name set 欄位 = 新值 where 欄位 = 值;

update 可以修改值但是檢視的值修改後 原資料也會被修改不建議使用

 

刪除檢視

drop view view_name

 

案例1: 簡化多表sql語句

#準備資料

create database db02 charset utf8;

use db02

create table student(

  s_id int(3),

  name varchar(20),

  math float,

  chinese float

);

insert into student values(1,'tom',80,70),(2,'jack',80,80),(3,'rose',60,75);

create table stu_info(

  s_id int(3),

  class varchar(50),

  addr varchar(100)

);

insert into stu_info values(1,'二班','安徽'),(2,'二班','湖南'),(3,'三班','黑龍江');

#建立檢視包含 編號 學生的姓名 和班級

create view stu_v (編號,姓名,班級) as

select

student.s_id,student.name ,stu_info.class

from student,stu_info

where student.s_id=stu_info.s_id;

# 檢視檢視中的資料

select *from stu_v;

然後以後就直接訪問stu_v就可以查詢出結果不用再打一次查詢程式碼.(一般簡單的查詢不會使用檢視直接寫where條件就可以)

 

 

案例2: 隔離資料

# 建立工資表
create table salarys(
id int primary key,
name char(10),
salary double,
dept char(10)
);
insert into salarys values
(1,"劉強東",900000,"市場"),
(2,"馬雲",800090,"市場"),
(3,"李彥巨集",989090,"財務"),
(4,"馬化騰",87879999,"財務");
# 建立市場部檢視
create view dept_sc as select *from salarys where dept = "市場";
# 檢視市場部檢視
select *from dept_sc;

使用者訪問dept_sc後就值可以訪問到某個欄位 可以限制使用者觀看的欄位數

 

二.觸發器

1什麼是觸發器

觸發器是一段與表有關的mysql程式 當這個表在某個時間點發生了某種事件時 將會自動執行相應的觸發器程式

 

2 什麼時候用觸發器

當我們想要在一個表記錄被更新時做一些操作時就可以使用觸發器

但是我們完全可以在python中來完成這個事情,因為python的擴充套件性更強,語法更簡單

 

CREATE TRIGGER t_name t_time t_event ON table_name FOR EACH ROW
begin
stmts.....
end

支援的時間點(t_time):時間發生前和發生前後 before|after

支援的事件(t_event): update insert delete

在觸發器中可以訪問到將被修改的那一行資料 根據事件不同 能訪問也不同 update 可用OLD訪問舊資料 NEW訪問新資料 insert 可用NEW訪問新資料 delete 可用OLD訪問舊資料

可以將NEW和OLD看做一個物件其中封裝了這列資料的所有欄位

案例:

有cmd表和錯誤日誌表,需求:在cmd執行失敗時自動將資訊儲存到錯誤日誌表中

 

#準備資料
CREATE TABLE cmd (
    id INT PRIMARY KEY auto_increment,
    USER CHAR (32),
    priv CHAR (10),
    cmd CHAR (64),
    sub_time datetime, #提交時間
    success enum ('yes', 'no') #0代表執行失敗
);
#錯誤日誌表
CREATE TABLE errlog (
    Id INT PRIMARY KEY auto_increment,
    err_cmd CHAR (64),
    err_time datetime
);
# 建立觸發器
delimiter //
create trigger trigger1 after insert on cmd for each row
begin
if new.success = "no" then
    insert into errlog values(null,new.cmd,new.sub_time);
end if;
end//
delimiter ;
#往表cmd中插入記錄,觸發觸發器,根據IF的條件決定是否插入錯誤日誌
INSERT INTO cmd (
    USER,
    priv,
    cmd,
    sub_time,
    success
)
VALUES
    ('egon','0755','ls -l /etc',NOW(),'yes'),
    ('egon','0755','cat /etc/passwd',NOW(),'no'),
    ('egon','0755','useradd xxx',NOW(),'no'),
    ('egon','0755','ps aux',NOW(),'yes');
# 檢視錯誤日誌表中的記錄是否有自動插入
select *from errlog;

delimiter 用於修改預設的行結束符 , ,後面跟什麼字元就修改成什麼字元.

由於在觸發器中有多條sql語句他們需要使用分號來結束,但是觸發器是一個整體,所以我們需要先更換預設的結束符,在觸發器編寫完後在將結束符設定回分號

 

注意:

外來鍵不能觸發事件 主表刪除了某個主鍵 從表也會相應刪除 但是並不會執行觸發器 觸發器中不能使用事務 相同時間點的相同事件的觸發器 不能同時存在

 

刪除觸發器

語法:

drop trigger trigger_name;

 

 

 

 

三.事物

什麼是事物

事務是邏輯上的一組操作,要麼都成功,要麼都失敗

 

為什麼需要事物

很多時候一個數據操作,不是一個sql語句就完成的,可能有很多個sql語句,如果部分sql執行成功而部分sql執行失敗將導致資料錯亂!

 

例如轉賬操作,

1.從原有賬戶減去轉賬金額

2.給目標賬戶加上轉賬金額

3若中間突然斷電了或系統崩潰了,錢就不翼而飛了!

 

使用事物

start transaction; --開啟事物,在這條語句之後的sql將處在同一事務,並不會立即修改數庫

commit;--提交事務,讓這個事物中的sql立即執行資料的操作,

rollback;--回滾事務,取消這個事物,這個事物不會對資料庫中的資料產生任何影響

 

案例:轉賬過程中發生異常

#準備資料
create table account(
    id int primary key auto_increment,
    name varchar(20),
    money double
);
insert into account values(1,'趙大兒子',1000);
insert into account values(2,'劉大牛',1000);
insert into account values(3,'豬頭三',1000);
insert into account values(4,'王進',1000);
insert into account values(5,'黃卉',1000);
# 趙大兒子劉大牛佳轉賬1000塊
# 未使用事務
update account set money = money - 1000 where id = 1;
update account set moneys = money - 1000 where id = 1; # money打錯了導致執行失敗

在用update等才做先要先start transaction啟動事物 然後操作完後可以使用rollback回滾事物,返回到上一次操作.但是rollback後事物也結束了需要再次啟動start transaction,不然再操作就不能rollback了. Commit是提交執行好的sql語句.

 

以下是在pycharm裡執行事物

import pymysql

conn = pymysql.connect(

        user = "root",

        password = "admin",

        database = "t3",

        charset = "utf8"

)

cursor = conn.cursor(pymysql.cursors.DictCursor)

# cursor.execute("select * from account")

# conn.commit()

sql = "update account set money = money - 100    where id = 2"

sq2 = "update account set moneys = money + 100    where id = 3"

try:

    cursor.execute(sql)

    cursor.execute(sq2)

    conn.commit()

    print("提交了!")

except:

    print("回滾了!")

conn.rollback()

pycharm會自動啟動事物

注意:事務的回滾的前提是能捕捉到異常,否則無法決定何時回滾,Python中很簡單就實現了,另外mysql中需要使用儲存過程才能捕獲異常!

 

事物的四個特性

原子性:

事務是一組不可分割的單位,要麼同時成功,要麼同時不成功

一致性:

事物前後的資料完整性應該保持一致,(資料庫的完整性:如果資料庫在某一時間點下,所有的資料都符合所有的約束,則稱資料庫為完整性的狀態);

隔離性:

 事物的隔離性是指多個使用者併發訪問資料時,一個使用者的事物不能被其它使用者的事務所幹擾,多個併發事務之間資料要相互隔離

永續性:

永續性是指一個事物一旦被提交,它對資料的改變就是永久性的,接下來即使資料庫發生故障也不應該對其有任何影響

 

事物的隔離級別

資料庫使用者可以控制資料庫工作在哪個級別下,就可與防止不同的隔離性問題

read uncommitted --不做任何隔離,可能髒讀,幻讀

read committed----可以防止髒讀,不能防止不可重複讀,和幻讀,

Repeatable read --可以防止髒讀,不可重複讀,不能防止幻讀 mysql預設級別

Serializable--資料庫執行在序列化實現,所有問題都沒有,就是效能低

髒讀:讀取到另一個事務未提交的資料,(比如說你淘寶買了個東西付錢了,賣家發貨了,然後你rollback回滾資料錢又回來了,這種問題屬於髒讀.資料沒有提交commit

不可重複讀 : 一個事務在查詢 一個在update   第一次查 和第二次查有可能資料不一樣

幻讀 :一個事務在查 另一個insert 或 delete 第一次查 和第二次查有可能記錄不一樣

修改隔離級別

select @@tx_isolation;--查詢當前級別

set[session|global] transaction isolation level .... ;修改級別

 

例項

set global transaction isolation level read committed;#退出mysql再進生效

 

四.儲存過程

 

什麼是儲存過程

儲存過程是一組任意的sql語句集合,儲存在mysql中,呼叫儲存過程時將會執行其包含的所有sql語句;與python中函式類似

 

為什麼使用儲存過程

回顧觸發器與檢視都是為了簡化應用程式中sql語句的書寫,但是還是需要編寫,而儲存過程中可以包含任何的sql語句,包括檢視,事務,流程控制等,這樣一來,應用程式可以從sql語句中完全解放,mysql可以替代應用程式完成資料相關的的邏輯處理!

那我們以後都是用儲存過程不就完了?

 

三種開發方式對比

1.應用程式僅負責業務邏輯編寫,所有與資料相關的邏輯都交給mysql來完成,通過儲存過程(推薦使用)

優點:

應用程式與資料處理完解耦合,一堆複雜的sql被封裝成了一個簡單的儲存過程,考慮到網路環境因素,效率高

應用程式開發者不需要編寫sql語句,開發效率高

缺點:

python語法與mysql語法區別巨大,學習成本高

並且各種資料庫的語法大不相同,所以移植性非常差

應用程式開發者與BDA的跨部門溝通成本高,造成整體效率低

 

2.應用程式不僅編寫業務邏輯,還需要編寫所有的sql語句

優點:擴充套件性高,對於應用程式開發者而言,擴充套件性和維護性相較於第一種都有所提高

缺點:sql語句過於複雜,導致開發效率低,且需要考慮sql'優化問題

 

3.應用程式僅負責業務邏輯,sql語句的編寫交給ORM框架,(常用解決方案)

優點:應用程式開發者不需要編寫sql語句,開發效率高

缺點:執行效率低,由於需要將物件的操作轉化為sql語句,且需要通過網路傳送大量sql

 

 

 

 

 

 

 

建立儲存過程

create procedure pro_name(p_Type p_name data_type)

begin

sql語句......流程控制

end

p_type 引數型別

in 表示輸入引數

out 表示輸出引數

inout表示既能輸入又能輸出

p_name 引數名稱

data_type 引數型別 可以是mysql支援的資料型別

 

案例:使用儲存過程完成對student表的查詢

delimiter //
create procedure p1(in m int,in n int,out res int)
begin
    select *from student where chinese > m and chinese < n;
    #select *from student where chineseXXX > m and chinese < n; 修改錯誤的列名以測試執行失敗
    set res = 100;
end//
delimiter ;
set @res = 0;
#呼叫儲存過程
call p1(70,80,@res);
#檢視執行結果
select @res;

需要注意的是,儲存過程的out類引數必須是一個變數,不能是值;

call p1(70,80,@res);第3個引數是out所以要設定變數set @res = 0;
輸出完後可以用select @res;查詢結果;
 

 

在python中呼叫儲存過程

import pymysql

#建立連線

conn = pymysql.connect(

        user = "root",

        password = "admin",

        database = "t3",

        charset = "utf8"

)

# 獲取遊標

cursor = conn.cursor(pymysql.cursors.DictCursor)

# 呼叫用儲存過程

cursor.callproc("p1",(50,80,0))#p1為儲存過程名 會自動為為每個值設定變數,名稱為 @_p1_0,@_p1_1,@_p1_2

# 提取執行結果是否有結果取決於儲存過程中的sql語句

print(cursor.fetchall())

# 獲取執行狀態

cursor.execute("select @_p1_2")

print(cursor.fetchone())

此處pymysql會自動將引數都設定一個變數所以可以直接傳入一個值,當然值如果作為輸出引數的話,傳入什麼都無所謂!

 

刪除儲存過程

drop procedure

修改儲存過程意義不大,不如刪除重寫!

檢視儲存過程

#當前庫所有儲存過程名稱
 select `name` from mysql.proc where db = 'db02' and `type` = 'PROCEDURE';
 #檢視建立語句
 show create procedure p1;

 

儲存過程中的事物應用

儲存過程中支援任何的sql語句包括事務!

案例:模擬轉賬中傳送異常,進行回滾

delimiter //

create PROCEDURE p5(

    OUT p_return_code tinyint

)

BEGIN

    DECLARE exit handler for sqlexception

    BEGIN

 

        set p_return_code = 1;

        rollback;

    END;

    # exit 也可以換成continue 表示傳送異常時繼續執行

    DECLARE exit handler for sqlwarning

    BEGIN

 

        set p_return_code = 2;

        rollback;

    END;

    START TRANSACTION;

    update account set money = money - 1000 where id = 1;

    #update account set moneys = money - 1000 where id = 1; # moneys欄位導致異常

    COMMIT;

    set p_return_code = 0; #0代表執行成功

END //

delimiter ;

#在mysql中呼叫儲存過程
set @res=123;
call p5(@res);
select @res;

總結:拋開溝通成本,學習成本,儲存過程無疑是效率最高的處理方式,面試會問,一些公司也有一些現存的儲存過程,重點掌握!

 

五.函式

語法:

CREATE FUNCTION f_name(paramters)
returns dataType;
return value;

說明: paramters 只能是in 輸入引數 引數名 型別 必須有返回值 不能呢加begin 和end returns 後面是返回值的型別 這裡不加分號 return 後面是要返回的值

 

案例: 將兩數相加

create function addfuntion(a int,b int)
returns int return a + b;
#執行函式
select addfuntion(1,1);

下面是轉大寫

create function UCASE (a char(10))#函式名要和方法名一致
returns char return a
#執行函式
select UCASE (“b”);

注意: 函式只能返回一個值 函式一般不涉及資料的增刪改查 就是一個通用的功能 呼叫自定義的函式 與呼叫系統的一致 不需要call 使用select 可獲得返回值 函式中不能使用sql語句 就像在java中不能識別sql語句一樣

 

在SQL 語句中,表示式可⽤於⼀些諸如SELECT語句的ORDER BY 或 DELETE或 UPDATE語句的

WHERE ⼦句或 SET語句之類的地⽅。使⽤⽂本值、column值、NULL值、函式、 操作符來書 寫

表示式。 本章敘述了可⽤於書寫MySQL表示式的函式和操作符。

這些內建函式⼤⼤提⾼了我們的開發效率

 

 

 

 

 

六.資料備份與回覆

使用mysqldump程式進行備份

可以選擇要備份哪些表 如果不指定代表 全部備份

#示例:
#單庫備份
mysqldump -u -p db_name [table_name,,,] > fileName.sql

mysqldump -uroot -padmin t3 > C:\Users\le\Desktop\a.sql #t3是資料客名

 

mysqldump -uroot -p123 db1 table1 table2 > db1-table1-table2.sql

mysqldump -uroot -padmin t3 account > C:\Users\le\Desktop\b.sql

#t3是資料客名account表名

 

#多庫備份
mysqldump -uroot -p123 --databases db1 db2 mysql db3 > db1_db2_mysql_db3.sql

mysqldump -uroot -padmin --databases t3 mysql t1>C:\Users\le\Desktop\c.sql

 

#備份所有庫
mysqldump -uroot -p123 --all-databases > all.sql

 

 

 

 

 

 

 

 

 

 

 

使用mysql進行恢復

  1. 退出資料庫後

mysql -u -p < filename.sql;

mysql -uroot -padmin < C:\Users\le\Desktop\a.sql

 

 

如果報錯說沒有選擇資料庫就要在讀取sql檔案裡寫

create database t3_copy;

use t3_copy;

 

  1. 不用退出資料庫

2.1    建立空資料庫

2.2選擇資料庫

2.3然後使用source filename; 來進行還原

use db1;

source /root/db1.sql

自己建立一個新的資料庫,進入資料庫執行source + 檔案路徑

source \Users\le\Desktop\a.sql;

 

資料庫遷移

務必保證在相同版本之間遷移

# mysqldump -h 源IP -uroot -p123 --databases db1 | mysql -h 目標IP -uroot -p456

 

七.流程控制

If語句的使用

if 條件 then 語句; end if; 第二種 if elseif if 條件 then 語句1; elseif 條件 then 語句2; else 語句3; end if;

案例:編寫過程 實現 輸入一個整數type 範圍 1 - 2 輸出 type=1 or type=2 or type=other;

create procedure showType(in type int,out result char(20))

begin

if type = 1 then

set result = "type = 1";

elseif type = 2 then

set result = "type = 2";

else

set result = "type = other";

end if;

end

 

case語句

大體意思與Swtich一樣的 你給我一個值 我對它進行選擇 然後執行匹配上的語句 語法:

create procedure caseTest(in type int)

begin

CASE type

when 1  then select "type = 1";

when 2  then select "type = 2";

else select "type = other";

end case;

end

 

定義變數

declare 變數名 型別 default 值; 例如: declare i int default 0;

 

WHILE迴圈

迴圈輸出10次hello mysql

create procedure showHello()

begin

declare i int default 0;

while  i < 10 do

select "hello mysql";

set i  = i + 1;

end while;

end

 

LOOP迴圈的

沒有條件 需要自己定義結束語句 語法:

輸出十次hello mysql;

create procedure showloop()

begin

declare i int default 0;

aloop: LOOP

select "hello loop";

set i = i + 1;

if i > 9 then leave aloop;

end if;

end LOOP aloop;

end

 

REPEAT迴圈

#類似do while

#輸出10次hello repeat

create procedure showRepeat()

begin

declare i int default 0;

repeat

select "hello repeat";

set i = i + 1;

until i > 9

end repeat;

end

#輸出0-100之間的奇數

create procedure showjishu()

begin

declare i int default 0;

aloop: loop

set i = i + 1;

if i >= 101 then leave aloop; end if;

if i % 2 = 0 then iterate aloop; end if;

select i;

end loop aloop;

end

重點內容: 儲存過程

事務