1. 程式人生 > 其它 >MySQL資料庫基礎6

MySQL資料庫基礎6

今日內容概要

  • SQL注入問題
  • 檢視
  • 觸發器
  • 事務
  • 儲存過程
  • 函式
  • 流程控制
  • 索引相關概念
  • 索引資料結構
  • 慢查詢優化

今日內容詳細

SQL注入問題

用python編寫簡易的基於資料庫的登陸註冊

怪像1:輸入使用者名稱就可以登入成功
怪像2:不需要對的使用者名稱和密碼也可以登入成功

SQL注入:利用特殊符號的組合產生特殊的含義 從而避開正常的業務邏輯

select * from userinfo where name='jason' --ojowno' and pwd=''
select * from userinfo where name='xyz' or 1=1 -- aksdfo' and pwd=''

針對上述的SQL注入問題 核心在於手動拼接了關鍵資料 交給execute處理即可避免
sql = " select * from userinfo where name=%s and pwd=%s "
coursor.execute(sql,(username, password))

'''
補充說明
	也可以一次性傳多個數據用executemany傳列表加元祖即可
	executemany(sql, [(),(),(),()...])
'''

檢視

檢視就是通過查詢得到一張虛擬表 然後儲存下來 下次直接使用

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

'''
1.檢視的表只能用來查詢不能做其他增刪改操作
2.檢視儘量少用 會跟真正的表產生混淆 從而干擾操作者
'''

觸發器

達到某個條件之後自動觸發執行
在MySQL中更加詳細的說明是觸發器:針對表執行增 刪 改操作後能夠自動觸發
主要有六種情況:增前 增後 刪前 刪後 改前 改後

create trigger 觸發器的名字 before/after insert/update/delete on 表名 for each row
begin
	sql語句
end

1.觸發器命名有一定的規律
	tir_before_insert_t1
	tir_after_delete_t2
	tir_after_update_t2
2.臨時修改SQL語句的結束符
	有些操作中需要使用分號

觸發器實際應用
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')
);

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('kevin','0755','ls -l /etc',NOW(),'yes'),
	  ('kevin','0755','cat /etc/passwd',NOW(),'no'),
	  ('kevin','0755','useradd xxx',NOW(),'no'),
    ('kevin','0755','ps aux',NOW(),'yes');

# 查詢errlog表記錄
select * from errlog;
# 檢視所有的觸發器
show triggers;
# 刪除觸發器
drop trigger tri_after_insert_cmd;

事務

事務的四大特性(ACID)
	A:原子性
		事務中的各項操作是不可分割的整體 要麼同時成功要麼同時失敗
	C:一致性
		使資料庫從一個一致性狀態變到另一個一致性狀態
	I:隔離性
		多個事務之間彼此不干擾
	D:永續性
		也稱永久性 指一個事務一旦提交 它對資料庫中資料的改變就應該是永久性的

create table user(
	id int primary key autp_increment,
	name char(32),
	balance int
);

insert into user(name,balance) values('jason',1000),('kevin',1000),('tom',1000);

# 修改資料之前先開啟事務操作
start transaction;

# 修改操作
update user set balance=900 where name='jason'; # 買家支付100元
update user set balance=1010 where name='kevin'; # 中介抽走10元
update user set balance=1090 where name='tom'; # 賣家收到90元

# 回滾到上一個狀態
rollback;

# 開啟事務之後 只要沒有執行commit操作 資料其實都沒有真正重新整理到硬碟 而是暫時存放在記憶體中
commit;

'''
事務相關關鍵字
	start transaction  開啟事務
	rollback  回滾
	commit   提交事務操作
	savepoint  儲存一個事務點
'''

在SQL標準中定義了四種隔離級別 每一種隔離級別都規定了一個事務中所做的修改
InnoDB支援所有的隔離級別
	set transaction isolation level 級別
1.read uncommitted(未提交讀)
	事務中的修改即使沒有提交 對其他事務也都是可見的 事務可以讀取未提交的資料 這一現象也稱之為'髒讀'
2.read committed(提交讀)
	大多數資料庫系統預設的隔離級別
	一個事務從開始到提交之前所做的任何修改對其他事務都是不可見的 這種級別也叫作"不可重複讀"
3.repeatable read(可重複讀)
	能夠解決'髒讀'問題 但是無法解決'幻讀'
	所謂幻讀指的是當某個事務在讀取某個範圍內的記錄時另外一個事務又在該範圍內插入了新的記錄 當之前的事務再次讀取該範圍內的記錄會產生幻行InnoDB和XtraDB通過多版本併發控制(MVCC)及間隙策略解決該問題
4.serializable(可序列讀)
	強制事務序列執行 很少使用該級別

MVCC只能在read committed(提交讀)和repeatable read(可重複讀)兩種隔離級別下工作 其他兩個不相容(read uncommitted:總是讀取最新  serializable:所有的行都加鎖)

InnoDB的MVCC通過在每行記錄後面儲存兩個隱藏的列來實現MVCC
	一個列儲存了行的建立時間
	一個列儲存了行的過期時間(或刪除時間) # 本質是系統版本號
沒開始一個新的事務版本號都會自動遞增 事務開始時刻的系統版本號會作為事務的版本號用來和查詢到的每行記錄版本號進行比較

例如
	剛插入第一條資料的時候 我們預設事務id為1 實際上是這樣儲存的
	username    create_version    delete_version
	jason          1
可以看到 我們在content列插入了kebe這條資料 在create_version這列儲存了1 1就是這次插入操作的事務id
	username    create_version    delete_version
	jason          1              2
	jason01         2              
可以看到 update的時候 會先將之前的資料delete_version標記為當前新的事務id 也就是2 然後將資料寫入 將新資料的create_version標記為新的事務id 當我們刪除資料的時候 實際儲存是這樣的
	username    create_version    delete_version
	jason01         2              3
'''
由此當我們查詢一條記錄的時候 只有滿足以下兩個條件的記錄才會被顯示出來
	1.當前事務id要大於或者等於當前行的create_version值 這表示在事務開始前這行資料已經存在了
	2.當前事務id要小於delete_version值 這表示在事務開始之後這行記錄才被刪除
'''

儲存過程

可以看成是python中的自定義函式

# 無參函式
delimiter $$
create procedure p1()
begin
	select * from cmd;
end $$
delimiter ;

# 定義
call p1()

# 有參函式
delimiter $$
create procedure p2(
	in m int,   # in表示這個引數必須只能是傳入不能被返回出去
	in n int,
	out res int  # out表示這個引數可以被返回出去 還有一個inout表示即可傳入也可以返回出去
)
begin
	select * from cmd where id > m and id < n;
	set res=0  # 用來標誌儲存過程是否執行
end $$
delimiter ;

# 針對set需要先提前定義
set @res=10;  定義
select @res;  檢視
call p2(1,5,@res);  呼叫
select @res;

'''
檢視儲存過程具體資訊
	show create procedure pro1;
檢視所有儲存過程
	show procedure status;
刪除儲存過程
	drop procedure p2;
'''

函式

可以看成是python中的內建函式

'''可以通過help 函式名    檢視幫助資訊'''

# 移除指定字元
Trim
LTrim
RTrim

# 大小寫轉換
Lower
Upper

# 獲取左右起始指定個數字元
Left
Right

# 返回讀音相似值(對英文效果)
Soundex
'''
客戶表中有一個顧客登記的使用者名稱為J.Lee
	但如果這是輸入錯誤了 真名其實叫J.Lie 可以使用soundex匹配發音類似的
	where Soundex(name)=Soundex('J.Lie')
'''

# 日期格式:date_format
'''在MySQL中表示時間格式 儘量採用2022-11-11形式'''
create table blog(
    id int primary key auto_increment,
    name char(32),
    sub_time datetime
);

insert into blog(name,sub_time) 
values
    ('第1篇','2015-03-01 11:31:21'),
    ('第2篇','2015-03-11 16:31:21'),
    ('第3篇','2016-07-01 10:21:31'),
    ('第4篇','2016-07-22 09:23:21'),
    ('第5篇','2016-07-23 10:11:11'),
    ('第6篇','2016-07-25 11:21:31'),
    ('第7篇','2017-03-01 15:33:21'),
    ('第8篇','2017-03-01 17:32:21'),
    ('第9篇','2017-03-01 18:31:21');
select date_format(sub_time,'%Y-%m'),count(id) from blog group by date_format(sub_time,'%Y-%m');

where Date(sub_time)='2015-03-01';
where Year(sub_time)=2016 and Moth(sub_time)=07;

# 更多日期處理相關函式
	adddate 增加一個日期
	addtime 增加一個時間
	datediff 計算兩個日期差值

流程控制

# 分支結構
declare i int default 0;
if i=1 then
    select 1;
elseif i=2 then
    select 2;
else
    select 7;
end if;

# 迴圈結構
declare num int;
set num=0;
while num<10 do
    select num;
    set num=num+1;
end while;

索引相關概念

索引就好比一本書的目錄 它能夠讓你更快的找到自己想要的內容
讓獲取的資料更有目的性 從而提高資料庫檢索資料的效能

索引在MySQL中也叫作'鍵' 是儲存引擎用於快速找到記錄的一種資料結構
	primary key
	unique key
	index key
1.上述的三個key都可以加快資料查詢
2.primary key和unique key除了可以加快查詢外本身還自帶限制條件而index key很單一 就是用來加快資料查詢
3.外來鍵不屬於索引鍵的範圍 是用來建立關係的 與加快查詢無關

索引加快查詢的本質
	select name from userinfo where phon=18888888888;  # 一頁頁的翻
	select name from userinfo where id=999;  # 按照目錄確定頁數找

索引可以加快資料查詢 但是會降低增刪速度
通常情況下我們頻繁使用某些欄位查詢資料 為了提升查詢的速度可以將該欄位建立索引

聚焦索引(primary key)
	主鍵 主鍵索引
輔助索引(unique,index)
	除了主鍵以外的都是輔助索引
覆蓋索引
	select name from user where name='jason';
非覆蓋索引
	select age from user where name='jason';

索引資料結構

索引底層其實是樹結構>>>:樹是計算機底層的資料結構

樹有很多型別
	二叉樹 b樹 b+樹 b*樹

二叉樹
	二叉樹裡面還可以細分成很多領域 我們簡單的瞭解即可
	二叉意味著每個節點最大隻能分兩個子節點
B樹
	所有節點都可以存放完整的資料
B+\B*樹
	只有葉子節點才會存放真正的資料 其他節點只存放索引資料
	B+葉子節點增加了指向其他葉子節點的指標
	B*葉子節點和枝節點都有指向葉子節點的指標

輔助索引在查詢資料的時候最後還是需要藉助於聚焦索引
	輔助索引葉子節點存放的是資料的主鍵值

有時候就算採用索引欄位查詢資料 也可能不會走索引
	最好能記三個左右的特殊情況

慢查詢優化

	EXPLAIN是MySQl必不可少的一個分析工具,主要用來測試sql語句的效能及對sql語句的優化,或者說模擬優化器執行SQL語句。在select語句之前增加explain關鍵字,執行後MySQL就會返回執行計劃的資訊,而不是執行sql
    
1.ALL 
	全表掃描
2.index 
	索引全掃描
3.range 
	索引範圍掃描,常用語<,<=,>=,between,in 等操作
4.ref 
	使用非唯一索引掃描或唯一索引字首掃描,返回單條記錄,常出現在關聯查詢中
5.eq_ref 
	類似 ref,區別在於使用的是唯一索引,使用主鍵的關聯查詢
6.const/system 
	單條記錄,系統會把匹配行中的其他列作為常數處理,如主鍵或唯一索引查詢
7.null
	不訪問任何表或索引,直接返回結果