數據庫高級

目錄

    視圖html

    觸發器python

    事務mysql

    存儲過程面試

    函數sql

     數據備份.恢復數據庫

     流程控制(瞭解)網絡

一.視圖

 

什麼是視圖

視圖是有一張表或多張表的查詢結果構成的一張虛擬表session

爲何使用視圖

當咱們在使用多表查詢時 咱們的sql語句可能會很是的複雜,若是每次都編寫一遍sql'的話無疑是一件麻煩的事情,這時候就可使用視圖來避免屢次編寫sql的問題;數據結構

簡答的說能夠幫咱們節省sql的編寫,併發

視圖的另外一個做用是,能夠不一樣的視圖來展現開放不一樣數據的訪問

例如,同一張工資表,老闆能夠查看所有,部門主管能夠查看該部門全部人,員工只能看本身的一條記錄

使用方法

建立視圖

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

加上OR REPLACE 時若是已經存在相同視圖則替換原有視圖

column_list指定哪些字段要出如今視圖中

注意:因爲是一張虛擬表,視圖中的數據實際上來源於其餘其餘表,因此在視圖中的數據不會出如今硬盤上

使用視圖

  視圖是一張虛擬表 因此使用方式與普通表沒有任何區別

查看視圖

  1.desc view_name; //查看數據結構

  2.show create view view_name;//查看 建立語句

修改視圖

  alter view_name select_statement

刪除視圖

  drop view view_name

案例1: 簡化多表sql語句

 1 #準備數據
 2 create database db02 charset utf8;
 3 use db02
 4 create table student(
 5   s_id int(3),
 6   name varchar(20),
 7   math float,
 8   chinese float 
 9 );
10 insert into student values(1,'tom',80,70),(2,'jack',80,80),(3,'rose',60,75);
11 12 create table stu_info(
13   s_id int(3),
14   class varchar(50),
15   addr varchar(100)
16 );
17 insert into stu_info values(1,'二班','安徽'),(2,'二班','湖南'),(3,'三班','黑龍江');
18 19 #建立視圖包含 編號 學生的姓名 和班級
20 create view stu_v (編號,姓名,班級) as 
21 select 
22 student.s_id,student.name ,stu_info.class
23 from student,stu_info 
24 where student.s_id=stu_info.s_id;
25 # 查看視圖中的數據
26 select *from stu_v; 

案例2: 隔離數據

 1 # 建立工資表
 2 create table salarys(
 3 id int primary key,
 4 name char(10),
 5 salary double,
 6 dept char(10)
 7 );
 8 insert into salarys values
 9 (1,"劉強東",900000,"市場"),
10 (2,"馬雲",800090,"市場"),
11 (3,"李彥宏",989090,"財務"),
12 (4,"馬化騰",87879999,"財務");
13 14 # 建立市場部視圖
15 create view dept_sc as select *from salarys where dept = "市場";
16 # 查看市場部視圖
17 select *from dept_sc;

注意:對視圖數據的insert update delete 會同步到原表中,但因爲視圖多是部分字段,不少時候會失敗

總結:mysql能夠分擔程序中的部分邏輯,但這樣一來後續的維護會變得更麻煩

若是須要改表結構,那意味着視圖也須要相應的修改,沒有直接在程序中修改sql來的方便

二.觸發器

 

什麼是觸發器

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

什麼時候使用觸發器

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

可是咱們徹底能夠在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看作一個對象其中封裝了這列數據的全部字段

案例:

 1 有cmd表和錯誤日誌表,需求:在cmd執行失敗時自動將信息存儲到錯誤日誌表中
 2 
 3 #準備數據
 4 CREATE TABLE cmd (
 5     id INT PRIMARY KEY auto_increment,
 6     USER CHAR (32),
 7     priv CHAR (10),
 8     cmd CHAR (64),
 9     sub_time datetime, #提交時間
10     success enum ('yes', 'no') #0表明執行失敗
11 );
12 #錯誤日誌表
13 CREATE TABLE errlog (
14     id INT PRIMARY KEY auto_increment,
15     err_cmd CHAR (64),
16     err_time datetime
17 );
18 # 建立觸發器
19 delimiter //
20 create trigger trigger1 after insert on cmd for each row
21 begin
22 if new.success = "no" then
23     insert into errlog values(null,new.cmd,new.sub_time);
24 end if;
25 end//
26 delimiter ;
27 28 #往表cmd中插入記錄,觸發觸發器,根據IF的條件決定是否插入錯誤日誌
29 INSERT INTO cmd (
30     USER,
31     priv,
32     cmd,
33     sub_time,
34     success
35 )
36 VALUES
37     ('egon','0755','ls -l /etc',NOW(),'yes'),
38     ('egon','0755','cat /etc/passwd',NOW(),'no'),
39     ('egon','0755','useradd xxx',NOW(),'no'),
40     ('egon','0755','ps aux',NOW(),'yes');
41 # 查看錯誤日誌表中的記錄是否有自動插入
42 select *from errlog;
43 ​ 

delimiter 用於修改默認的行結束符 ,因爲在觸發器中有多條sql語句他們須要使用分號來結束,可是觸發器是一個總體,因此咱們須要先更換默認的結束符,在觸發器編寫完後在將結束符設置回分號

注意:

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

刪除觸發器

語法:
drop trigger trigger_name;
案例:
drop trigger trigger1;

一樣的這種需求咱們徹底能夠在python中來完成! mysql最想完成的事情是講全部能處理的邏輯所有放到mysql中,那樣一來應用程序開發者的活兒就變少了,相應的數據庫管理員的工資就高了,惋惜大多中小公司都沒有專門的DBA;

三.事務

 

什麼是事務

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

爲何須要事務

  不少時候一個數據操做,不是一個sql語句就完成的,可能有不少個sql語句,若是部分sql執行成功而部分sql執行失敗將致使數據錯亂!

例如轉帳操做,

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

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

  若中間忽然斷電了或系統崩潰了,錢就不知去向了!

使用事務

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

  commit;--提交事務,讓這個事物中的sql當即執行數據的操做,

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

 案例:轉帳過程當中發生異常

 1 #準備數據
 2 create table account(
 3     id int primary key auto_increment,
 4     name varchar(20),
 5     money double
 6 );
 7 insert into account values(1,'趙大兒子',1000);
 8 insert into account values(2,'劉大牛',1000);
 9 insert into account values(3,'豬頭三',1000);
10 insert into account values(4,'王進',1000);
11 insert into account values(5,'黃卉',1000);
12 13 # 趙大兒子劉大牛佳轉帳1000塊
14 # 未使用事務
15 update account set money = money - 1000 where id = 1;
16 update account set moneys = money - 1000 where id = 1; # money打錯了致使執行失敗
17 18 # 在python中使用事務處理
19 sql = 'update account set money = money - 1000 where id = 1;'
20 sql2 = 'update account set moneys = money + 1000 where id = 2;' # money打錯了致使執行失敗
21 try:
22     cursor.execute(sql)
23     cursor.execute(sql2)
24     conn.commit()
25 except:
26     conn.rollback() 

注意:事務的回滾的前提是能捕捉到異常,不然沒法決定什麼時候回滾,Python中很簡單就實現了,另外mysql中須要使用存儲過程才能捕獲異常!

事務的四個特性:

  原子性:

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

  一致性:

    ​ 事物先後的數據完整性應該保持一致,(數據庫的完整性:若是數據庫在某一時間點下,全部的數據都符合全部的約束,則稱數據庫爲完整性的狀態);

  隔離性:

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

  持久性:

    ​ 持久性是指一個事物一旦被提交,它對數據的改變就是永久性的,接下來即便數據庫發生故障也不該該對其有任何影響

併發容易出現的問題:

  丟失更新:

    當兩個或多個事務選擇同一行,而後基於最初選定的值更新該行時,因爲每一個事務都不知道其餘事務的存在,就會發生丟失更新

  髒讀:

    一個事務正在對一條記錄作修改,在這個事務完成並提交前,有另外一個事務進行讀取,就會產生髒讀

  不可重複讀:

    當一個事務屢次讀取同一行,可是每次讀取到不一樣數據時.會發生不可重複讀.

  幻讀:

    當一個事務對某行執行插入或刪除操做,而該行屬於某個事務正在讀取的行的範圍時,會幻讀

事務的用戶隔離級別:

  數據庫使用者能夠控制數據庫工做在哪一個級別下,就可與防止不一樣的隔離性問題

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

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

  Repeatable read --能夠防止髒讀,不可重複讀,不能防止幻讀

  Serializable--數據庫運行在串行化實現,全部問題都沒有,就是性能低

修改隔離級別:

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

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

 實例:

  set global transaction isolation level Repeatable read ;

四.存儲過程

 

什麼是存儲過程

  存儲過程是一組任意的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表的查詢

 1 delimiter //
 2 create procedure p1(in m int,in n int,out res int)
 3 begin
 4     select *from student where chinese > m and chinese < n;
 5     #select *from student where chineseXXX > m and chinese < n; 修改錯誤的列名以測試執行失敗
 6     set res = 100;
 7 end//
 8 delimiter ;
 9 set @res = 0;
10 #調用存儲過程
11 call p1(70,80,@res);
12 #查看執行結果
13 select @res;
14  
15 須要注意的是,存儲過程的out類參數必須是一個變量,不能是值;
16 
17 在python中調用存儲過程
18  
24 import  pymysql
25 #創建鏈接
26 conn = pymysql.connect(
27     host="127.0.0.1",
28     user="root",
29     password="admin",
30     database="db02"
31 )
32 # 獲取遊標
33 cursor = conn.cursor(pymysql.cursors.DictCursor)
34 35 # 調用用存儲過程
36 cursor.callproc("p1",(70,80,0)) #p1爲存儲過程名 會自動爲爲每一個值設置變量,名稱爲 @_p1_0,@_p1_1,@_p1_2
37 # 提取執行結果是否有結果取決於存儲過程當中的sql語句
38 print(cursor.fetchall())
39 # 獲取執行狀態
40 cursor.execute("select @_p1_2")
41 print(cursor.fetchone())

此處pymysql會自動將參數都設置一個變量因此能夠直接傳入一個值,固然值若是做爲輸出參數的話,傳入什麼都無所謂!

刪除存儲過程

drop procedure 過程名稱;

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

查看存儲過程

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

存儲過程當中的事務應用

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

案例:模擬轉帳中發送異常,進行回滾

 1 delimiter //
 2 create PROCEDURE p5(
 3     OUT p_return_code tinyint
 4 )
 5 BEGIN 
 6     DECLARE exit handler for sqlexception 
 7     BEGIN 
 8         -- ERROR 
 9         set p_return_code = 1; 
10         rollback; 
11     END; 
12     # exit 也能夠換成continue 表示發送異常時繼續執行
13     DECLARE exit handler for sqlwarning 
14     BEGIN 
15         -- WARNING 
16         set p_return_code = 2; 
17         rollback; 
18     END; 
19 20     START TRANSACTION; 
21     update account set money = money - 1000 where id = 1;
22     update account set moneys = money - 1000 where id = 1; # moneys字段致使異常
23     COMMIT; 
24 25     -- SUCCESS 
26     set p_return_code = 0; #0表明執行成功
27 28 END //
29 delimiter ;
30 31 #在mysql中調用存儲過程
32 set @res=123;
33 call p5(@res);
34 select @res;
35

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

五.函數

MySQL中提供了許多內置函數,例如:

  View Code
  須要掌握函數:date_format

更多函數:中文猛擊這裏 OR 官方猛擊這裏

一 自定義函數

#!!!注意!!!
#函數中不要寫sql語句(不然會報錯),函數僅僅只是一個功能,是一個在sql中被應用的功能
#若要想在begin...end...中寫sql,請用存儲過程
  View Code
  View Code

二 刪除函數

  View Code

三 執行函數

  View Code

六.數據備份與恢復

 

使用mysqldump程序進行備份

mysqldump -u -p db_name [table_name,,,] > fileName.sql

能夠選擇要備份哪些表 若是不指定表明 所有備份

#示例:
#單庫備份
mysqldump -uroot -p123 db1 > db1.sql
mysqldump -uroot -p123 db1 table1 table2 > db1-table1-table2.sql
​
#多庫備份
mysqldump -uroot -p123 --databases db1 db2 mysql db3 > db1_db2_mysql_db3.sql
​
#備份全部庫
mysqldump -uroot -p123 --all-databases > all.sql 

使用 mysql 進行恢復

1.退出數據庫後

  mysql -u -p < filename.sql;

2.不用退出數據庫

​   2.1 建立空數據庫

  ​ 2.2選擇數據庫

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

use db1;
source /root/db1.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;

 1 create procedure showType(in type int,out result char(20))
 2 begin
 3 if type = 1 then 
 4 set result = "type = 1";
 5 elseif type = 2 then 
 6 set result = "type = 2";
 7 else 
 8 set result = "type = other";
 9 end if;
10 end

CASE 語句

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

1 create procedure caseTest(in type int)
2 begin
3 CASE type 
4 when 1  then select "type = 1";
5 when 2  then select "type = 2";
6 else select "type = other";
7 end case;
8 end

定義變量

declare 變量名 類型 default 值; 例如: declare i int default 0;

WHILE循環

1 循環輸出10次hello mysql
2 create procedure showHello()
3 begin 
4 declare i int default 0;
5 while  i < 10 do
6 select "hello mysql";
7 set i  = i + 1;
8 end while;
9 end

LOOP循環的

沒有條件 須要本身定義結束語句 語法:

 1 輸出十次hello mysql;
 2 create procedure showloop()
 3 begin 
 4 declare i int default 0;
 5 aloop: LOOP
 6 select "hello loop";
 7 set i = i + 1;
 8 if i > 9 then leave aloop;
 9 end if;
10 end LOOP aloop;
11 end 

REPEAT循環

 1 #相似do while
 2 #輸出10次hello repeat
 3 create procedure showRepeat()
 4 begin
 5 declare i int default 0;
 6 repeat
 7 select "hello repeat";
 8 set i = i + 1;
 9 until i > 9
10 end repeat;
11 end
12 13 #輸出0-100之間的奇數
14 create procedure showjishu()
15 begin
16 declare i int default 0;
17 aloop: loop
18 set i = i + 1;
19 if i >= 101 then leave aloop; end if;
20 if i % 2 = 0 then iterate aloop; end if;
21 select i;
22 end loop aloop;
23 end
相關文章
相關標籤/搜索