1. 程式人生 > 其它 >python四十四期---

python四十四期---

昨日內容回顧

  • 多表查詢的兩種方式

    連表操作
    	inner join
     	left join
     	right join
    	ps:所需結論來自於多張表的欄位 建議使用連表
    子查詢
    	將SQL語句括號括起來當做另外一條SQL語句的條件
    	ps:所需結論來自於一張表的欄位 可以使用子查詢
    '''甚至兩者在複雜SQL查詢中需要混合使用'''
    
  • 小知識點的補充說明

    1.拼接相關操作
    	concat()  concat_ws()  group_concat()
    2.關鍵字exists
    	sql1 exists sql2
     	"""
     	if sql2:sql1
     	"""
    3.針對表操作的SQL補充
    	alter table 表名 rename\add\change\modify\drop 
    
  • 視覺化軟體之Navicat

    1.下載與安裝
    2.基本使用
    	連結、建立、庫、表、記錄、外來鍵
    	逆向資料庫到模型
     	新建查詢
     	執行、轉儲SQL檔案
    
  • 多表查詢練習題

    1.先確定需要涉及到幾張表
    2.大致預覽表結構與表資料
    3.根據已知條件確定切入點
    4.靈活運用所學內容去拼湊
    	將複雜的操作流程化 步驟化
    ps:一定要自己多練多敲
    
  • pymysql模組

    pip3 install pymysql
    
    
    import pymysql
    conn = pymysql.connect(
    	host,port,user,password/passwd,database/db,charset,autocommit
    )
    cursor = conn.cursor(...)
    cursor.execute(sql)
    cursor.fetchall()
    
    1.獲取執行結果的方法也有類似於檔案游標的特性
    2.針對增、刪、改操作需要二次確認
    	conn.commit()
      	autocommit = True
    

今日內容概要

  • SQL注入問題
  • 檢視
  • 觸發器
  • 儲存過程
  • 流程控制
  • 內建函式
  • 索引與慢查詢優化

今日內容詳細

SQL注入問題

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

SQL注入:利用特殊符合的組合產生特殊的含義 從而避開正常的業務邏輯
select * from userinfo where name='jason' -- kasdjksajd' and pwd=''
select * from userinfo where name='xyz' or 1=1 -- aksdjasldj' and pwd='' 

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

'''
補充說明
	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.觸發器命名有一定的規律
	tri_before_insert_t1
  	tri_after_delete_t2
 	tri_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') #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
    ('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 auto_increment,
name char(32),
balance int
);

insert into user(name,balance)
values
('jason',1000),
('kevin',1000),
('tank',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='tank'; #賣家拿到90元

# 回滾到上一個狀態
rollback;

# 開啟事務之後,只要沒有執行commit操作,資料其實都沒有真正重新整理到硬碟
commit;

"""
事務相關關鍵字
	start transaction;
	rollback
	commit
	savepoint
"""
在SQL標準中定義了四種隔離級別,每一種級別都規定了一個事務中所做的修改
InnoDB支援所有隔離級別
	set transaction isolation level 級別
1.read uncommitted(未提交讀)
	事務中的修改即使沒有提交,對其他事務也都是可見的,事務可以讀取未提交的資料,這一現象也稱之為"髒讀"
2.read committed(提交讀)
	大多數資料庫系統預設的隔離級別
  一個事務從開始直到提交之前所作的任何修改對其他事務都是不可見的,這種級別也叫做"不可重複讀"
3.repeatable read(可重複讀)		# MySQL預設隔離級別
	能夠解決"髒讀"問題,但是無法解決"幻讀"
  所謂幻讀指的是當某個事務在讀取某個範圍內的記錄時另外一個事務又在該範圍內插入了新的記錄,當之前的事務再次讀取該範圍的記錄會產生幻行,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列插入了kobe這條資料,在create_version這列儲存了1,1是這次插入操作的事務id。
然後我們將jason修改為jason01,實際儲存是這樣的
    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 ;

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

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

# 大前提:儲存過程在哪個庫下面建立的只能在對應的庫下面才能使用!!!

# 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;')

函式

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

"ps:可以通過help 函式名    檢視幫助資訊!"
# 1.移除指定字元
Trim、LTrim、RTrim

# 2.大小寫轉換
Lower、Upper

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

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

# 5.日期格式: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');

1.where Date(sub_time) = '2015-03-01'
2.where Year(sub_time)=2016 AND Month(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 ;

索引相關概念

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

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

索引加快查詢的本質
	id int primary key auto_increment,
 	name varchar(32) unique,
  	province varchar(32)
 	age int
 	phone bigint
 	
	select name from userinfo where phone=18818888888;  # 一頁頁的翻
	select name from userinfo where id=99999;  # 按照目錄確定頁數找

索引可以加快資料查詢 但是會降低增刪的速度
通常情況下我們頻繁使用某些欄位查詢資料
	為了提升查詢的速度可以將該欄位建立索引
    
聚集索引(primary key)
	主鍵、主鍵索引
輔助索引(unique,index)
	除主鍵意外的都是輔助索引
覆蓋索引
	select name from user where name='jason';
非覆蓋索引
	select age from user where name='jason';

作業

1.課下自行百度學習什麼是資料庫三大正規化
2.整理今日內容及部落格