MySQL之事務以及存儲過程


今日內容

  • 視圖

  • 觸發器

  • 事務

  • 存儲過程

  • 內置函數

  • 流程控制

  • 索引

視圖

1、什么是視圖

    視圖就是通過查詢得到一張虛擬表,然后保存下來,下次直接使用即可

2、為什么要用視圖

    如果要頻繁使用一張虛擬表,可以不用重復查詢

3、如何用視圖

create view teacher2course as
select * from teacher inner join course on teacher.tid = course.teacher_id;

強調
1、在硬盤中,視圖只有表結構文件,沒有表數據文件
2、視圖通常是用於查詢,盡量不要修改視圖中的數據

drop view teacher2course;

思考:開發過程中會不會去使用視圖?

不會!視圖是mysql的功能,如果你的項目里面大量的使用到了視圖,那意味着你后期想要擴張某個功能的時候這個功能恰巧又需要對視圖進行修改,意味着你需要先在mysql這邊將視圖先修改一下,然后再去應用程序中修改對應的sql語句,這就涉及到跨部門溝通的問題,所以通常不會使用視圖,而是通過重新修改sql語句來擴展功能。

觸發器

在滿足對某張表數據的增、刪、改的情況下,自動觸發的功能稱之為觸發器

為何要用觸發器

    觸發器專門針對我們對某一張表數據增insert、刪delete、改update的行為,這類行為一旦執行
​    就會觸發觸發器的執行,即自動運行另外一段sql代碼

創建觸發器語法

# 針對插入
create trigger tri_after_insert_t1 after insert on 表名 for each row
begin
    sql代碼。。。
end
create trigger tri_after_insert_t2 before insert on 表名 for each row
begin
    sql代碼。。。
end
# 針對刪除
create trigger tri_after_delete_t1 after delete on 表名 for each row
begin
    sql代碼。。。
end
create trigger tri_after_delete_t2 before delete on 表名 for each row
begin
    sql代碼。。。
end
# 針對修改
create trigger tri_after_update_t1 after update on 表名 for each row
begin
    sql代碼。。。
end
create trigger tri_after_update_t2 before update on 表名 for each row
begin
    sql代碼。。。
end
# 案例
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 $$  # 將mysql默認的結束符由;換成$$
create trigger tri_after_insert_cmd after insert on cmd for each row
begin
    if NEW.success = 'no' then  # 新記錄都會被MySQL封裝成NEW對象
        insert into errlog(err_cmd,err_time) values(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');
# 查詢errlog表記錄
select * from errlog;
 刪除觸發器
drop trigger tri_after_insert_cmd;

事務

什么是事務

    開啟一個事務可以包含一些sql語句,這些sql語句要么同時成功
​    要么一個都別想成功,稱之為事務的原子性

事務的作用

保證了對數據操作的數據安全性

案例:用交行的卡操作建行ATM機給工商的賬戶轉錢

事務應該具有4個屬性:原子性、一致性、隔離性、持久性。這四個屬性通常稱為ACID特性

原子性(atomicity)。一個事務是一個不可分割的工作單位,事務中包括的諸操作要么都做,要么都不做。

一致性(consistency)。事務必須是使數據庫從一個一致性狀態變到另一個一致性狀態。一致性與原子性是密切相關的。

隔離性(isolation)。一個事務的執行不能被其他事務干擾。即一個事務內部的操作及使用的數據對並發的其他事務是隔離的,並發執行的各個事務之間不能互相干擾。

持久性(durability)。持久性也稱永久性(permanence),指一個事務一旦提交,它對數據庫中數據的改變就應該是永久性的。接下來的其他操作或故障不應該對其有任何影響。

如何用?

create table user(
id int primary key auto_increment,
name char(32),
balance int
);
insert into user(name,balance)
values
('wsb',1000),
('egon',1000),
('ysb',1000);
# 修改數據之前先開啟事務操作
start transaction;
# 修改操作
update user set balance=900 where name='wsb'; #買支付100元
update user set balance=1010 where name='egon'; #中介拿走10元
update user set balance=1090 where name='ysb'; #賣家拿到90元
# 回滾到上一個狀態
rollback;
# 開啟事務之后,只要沒有執行commit操作,數據其實都沒有真正刷新到硬盤
commit;
"""開啟事務檢測操作是否完整,不完整主動回滾到上一個狀態,如果完整就應該執行commit操作"""
# 站在python代碼的角度,應該實現的偽代碼邏輯,
try:
    update user set balance=900 where name='wsb'; #買支付100元
    update user set balance=1010 where name='egon'; #中介拿走10元
    update user set balance=1090 where name='ysb'; #賣家拿到90元
except 異常:
    rollback;
else:
    commit;
# 那如何檢測異常?

存儲過程

存儲過程包含了一系列可執行的sql語句,存儲過程存放於MySQL中,通過調用它的名字可以執行其內部的一堆sql

三種開發模型

第一種

"""
應用程序:只需要開發應用程序的邏輯
mysql:編寫好存儲過程,以供應用程序調用
優點:開發效率,執行效率都高
缺點:考慮到人為因素、跨部門溝通等問題,會導致擴展性差
"""

第二種

"""
應用程序:除了開發應用程序的邏輯,還需要編寫原生sql
優點:比方式1,擴展性高(非技術性的)
缺點:
1、開發效率,執行效率都不如方式1
2、編寫原生sql太過於復雜,而且需要考慮到sql語句的優化問題
"""

第三種

"""
應用程序:開發應用程序的邏輯,不需要編寫原生sql,基於別人編寫好的框架來處理數據,ORM
優點:不用再編寫純生sql,這意味着開發效率比方式2高,同時兼容方式2擴展性高的好處
缺點:執行效率連方式2都比不過
"""

創建存儲過程

delimiter $$
create procedure p1(
   in m int,  # in表示這個參數必須只能是傳入不能被返回出去
   in n int,  
   out res int  # out表示這個參數可以被返回出去,還有一個inout表示即可以傳入也可以被返回出去
)
begin
   select tname from teacher where tid > m and tid < n;
   set res=0;
end $$
delimiter ;

# 小知識點補充,當一張表的字段特別多記錄也很多的情況下,終端下顯示出來會出現顯示錯亂的問題
select * from mysql.user\G;

如何用存儲過程

# 大前提:存儲過程在哪個庫下面創建的只能在對應的庫下面才能使用!!!
# 1、直接在mysql中調用
set @res=10  # res的值是用來判斷存儲過程是否被執行成功的依據,所以需要先定義一個變量@res存儲10
call p1(2,4,10);  # 報錯
call p1(2,4,@res); 
# 查看結果
select @res;  # 執行成功,@res變量值發生了變化
# 2、在python程序中調用
pymysql鏈接mysql
產生的游表cursor.callproc('p1',(2,4,10))  # 內部原理:@_p1_0=2,@_p1_1=4,@_p1_2=10;
cursor.excute('select @_p1_2;')

# 3、存儲過程與事務使用舉例(了解)
delimiter //
create PROCEDURE p5(
    OUT p_return_code tinyint
)
BEGIN
    DECLARE exit handler for sqlexception
    BEGIN
        -- ERROR
        set p_return_code = 1;
        rollback;
    END;

  DECLARE exit handler for sqlwarning
  BEGIN
      -- WARNING
      set p_return_code = 2;
      rollback;
  END;
  START TRANSACTION;
      update user set balance=900 where id =1;
      update user123 set balance=1010 where id = 2;
      update user set balance=1090 where id =3;
  COMMIT;
  -- SUCCESS
  set p_return_code = 0; #0代表執行成功

END //
delimiter 
 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM