MySQL(檢視、觸發器、事務、儲存過程、索引)
阿新 • • 發佈:2022-05-09
MySQL(檢視、觸發器、事務、儲存過程、索引)
python操作MySQL
# python中支援操作MySQL的模組很多 其中最常見的當屬'pymysql' 為了使python連線上資料庫,你需要一個驅動,這個驅動是用於與資料庫互動的庫 PyMySQL : 這是一個使Python連線到MySQL的庫,它是一個純Python庫(資料夾) PyMySQL 是一個純 Python 實現的 MySQL 客戶端操作庫,支援事務、存取過程、批量執行,實現增刪改查等 # 下載方式 1.命令列輸入(下載模組 pymysql) pip3 install pymysql 2.切換下載的源(倉庫) pip3 install pymysql -i 源地址
pymysql的基本使用
import pymysql # 連結服務端 conn_obj = pymysql.connect( # 賦值給 conn連線物件 host='127.0.0.1', # MySQL服務端的IP地址 port=3306, # MySQL預設PORT地址(埠號) user='root', # 使用者名稱 password='123', # 密碼 也可以簡寫 passwd database='db_01', # 連線資料庫名稱 也可以簡寫 db charset='utf8' # 字元編碼 不能寫utf-8 ) # 生成一個獲取命令的遊標物件(相當於cmd開啟mysql中的 mysql>) cursor = conn.cursor( cursor=pymysql.cursors.DictCursor ) # 括號內不寫引數 資料是元組要元組 不夠精確 新增引數則會將資料處理成字典 # 定義SQL語句 sql = 'select * from teacher' # 執行SQL語句 affect_rows = cursor.execute(sql) print(affect_rows) # 執行SQL語句之後受影響的行數 # 獲取返回結果 res = cursor.fetchall() print(res)
excute返回值
1.execute返回值是執行SQL語句之後受影響的行數 2.fetchall()獲取所有的結果 fetchone()獲取結果集第一個結果 fetchmany()括號內可以指定獲取幾個結果集 # 獲取返回結果 # res = cursor.fetchall() # 列表套字典 # res = cursor.fetchone() # 資料字典 # res = cursor.fetchmany(3) # 列表套字典 cursor.scroll(1, 'relative') # 相對於當前位置往後移動一個單位 cursor.scroll(1, 'absolute') # 相對於起始位置往後移動一個單位
SQL注入問題
基本登入程式碼
import pymysql
# 建立連結
conn = pymysql.connect(
host='127.0.0.1',
port=3306,
user='root',
password='123',
database='db_01',
charset='utf8'
)
# 生成一個遊標物件
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) # 讓資料自動組織成字典
# 獲取使用者名稱和密碼
username = input('username>>>:').strip()
password = input('password>>>:').strip()
# 構造SQL語句
sql = "select * from egg where name='%s' and password='%s'"%(username,password)
print(sql)
# 執行sql語句
cursor.execute(sql)
# 獲取所有返回結果
res = cursor.fetchall()
# if判斷
if res:
print(res)
print('登入成功')
else:
print('使用者名稱或密碼錯誤')
注入問題發現
# 寫正確的使用者名稱錯誤的密碼也可以登入
使用者名稱:jason' -- jhahsdjasdjasd
密碼:直接回車
# 使用者名稱和密碼都不需要也可以登入
使用者名稱:xxx' or 1=1 -- asdjasjdkajsd
密碼:直接回車
"""上述現象就是典型的SQL注入問題"""
上述情況利用的是MySQL註釋語法及邏輯運算子
就是通過一線特殊符號的組合 達到某些特定的效果從而避免常規的邏輯
解決注入問題
#execute方法
自動將 使用者名稱和密碼放在對應的%s內,並且放之前會自動對使用者名稱和密碼做特殊符號的校驗,確保安全性
'''execute方法自帶校驗SQL注入問題 自動處理特殊符號
設計到敏感資料的拼接 全部交給execute方法即可'''
# 程式碼修改:
sql = "select * from userinfo where name=%s and password=%s;"
cursor.execute(sql, (name, password))
# execute批量插入資料
sql = 'insert into userinfo(name,password) values(%s,%s)'
cursor.executemany(sql,[('tom',123),('lavin',321), ('pony',333)])
commit()二次確認
#資料的增刪改查四個操作
查 不會影響真正的資料 重要程度最低
增、改、刪 都會影響真正的資料 重要程度較高
'''pymysql針對增、改、刪三個操作 都設定了二次確認 如果不確認則不會真正影響資料庫'''
# 方式1:程式碼直接編寫
affect_row = cursor.execute(sql)
conn_obj.commit() # 手動二次確認
# 方式2:配置固定引數
conn_obj = pymysql.connect(
host='127.0.0.1',
port=3306,
user='root',
password='jason123',
database='jp04_3',
charset='utf8',
autocommit=True # 自動二次確認
)
修改表SQL語句
# 1.修改表的名字 rename
alter table t1 rename ttt;
# 2.新增欄位 add
alter table ttt add pwd int; '''預設是尾部追加欄位'''
alter table ttt add tid int after name; '''指定追加位置'''
alter table ttt add nid int first; '''指定頭部新增欄位'''
# 3.修改欄位 change(名字型別都可)/modify(只能改型別不能改名字)
alter table ttt change pwd password tinyint;
# 4.刪除欄位 drop
alter table ttt drop nid;
檢視
# 檢視的概念
檢視是虛擬的表
# 檢視的建立
create view 檢視名 as sql語句
'''檢視雖然看似很好用 但是會造成表的混亂 畢竟檢視不是真正的資料來源
檢視只能用於資料的查詢 不能做增、刪、改的操作 可能會影響原始資料(視圖裡面的資料是直接來源於原始表 而不是拷貝一份) '''
觸發器
# 觸發器概念
在對錶資料進行增、刪、改的具體操作下,自動觸發的功能
# 觸發器作用
專門針對表資料的操作 定製個性化配套功能
# 觸發器種類
表資料新增之前、新增之後
表資料修改之前、修改之後
表資料刪除之前、刪除之後
# 觸發器建立
create trigger 觸發器名字 before/after insert/update/delete
on 表名 for each row
begin
SQL語句
end
# 觸發器的命名規範
tri_after_insert_t1
tri_before_update_t2
tri_before_delete_t3
'''更直觀的看出觸發器的作用'''
# 檢視當前庫下所有的觸發器資訊
show triggers\G;
# 刪除當前庫下指定的觸發器資訊
drop trigger 觸發器名稱;
觸發器具體案例
建立表
'''
臨時修改SQL語句的結束符
delimiter $$
臨時修改的原因是因為觸發器 儲存過程等技術點 程式碼中也需要使用分號
如果不修改 則無法書寫出完成的程式碼
'''
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
);
需求
cmd表插入資料的success如果值為no 則去errlog表中插入一條記錄
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 ; # 結束之後記得再改回來,不然後面結束符就都是$$了
3.僅僅往cmd表中插入資料
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');
事務
# 事務的概念
資料庫事務(Database Transaction),是指作為單個邏輯工作單元執行的一系列操作,要麼完全地執行,要麼完全地不執行。
簡單的說:事務就是將一堆的SQL語句(通常是增刪改操作)繫結在一起執行,要麼都執行成功,要麼都執行失敗,即都執行成功才算成功,否則就會恢復到這堆SQL語句執行之前的狀態。
事務的四個特性ACID
# A:原子性(Atomicity)
一個事務是一個不可分割的整體 裡面的操作要麼都成立要麼都不成立
# C:一致性(Consistency)
事務必須使資料庫從一個一致性狀態變到另外一個一致性狀態
# I:隔離性(Isolation,又稱獨立性)
併發程式設計中 多個事務之間是相互隔離的 不會彼此干擾
# D:永續性(Durability)
事務一旦提交 產生的結果應該是永久的 不可逆的
隔離級別
# 讀未提交(Read uncommitted)
安全性最差,可能發生併發資料問題,效能最好
# 讀提交(read committed)
Oracle預設的隔離級別
# 可重複讀(repeatable read)
MySQL預設的隔離級別,安全性較好,效能一般
# 序列化(Serializable)
表級鎖,讀寫都加鎖,效率低下,安全性高,不能併發
事務具體案例
建立表錄入資料
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;
# 編寫SQL語句(同屬於一個事務)
update user set balance=900 where name='jason';
update user set balance=1010 where name='kevin';
update user set balance=1090 where name='tank';
# 事務回滾(返回執行事務操作之前的資料庫狀態)
rollback; # 執行完回滾之後 事務自動結束
# 事務確認(執行完事務的主動操作之後 確認無誤之後 需要執行確認命令)
commit; # 執行完確認提交之後 無法回滾 事務自動結束
'''
事務操作步驟:
開啟事務:start transaction;
需要執行的SQL語句集
結束事務:commit(提交事務)或rollback(回滾事務)
'''
儲存過程
# 儲存過程的概念
本質上就是將一段SQL程式碼封裝起來,用於完成特定的操作,在使用時只需通過儲存過程的名稱呼叫即可(如果儲存過程需要引數的話還需要傳遞對應的引數)
# 類似於有參函式
delimiter $$
create procedure p1(
in m int, # in表示這個引數必須只能是傳入不能被返回出去
in n int,
out res int # out表示這個引數可以被返回出去,還有一個inout表示即可以傳入也可以被返回出去
)
begin
select tname from userinfo 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;
無參無返回值的儲存過程
# 相當於定義函式
delimiter $$
create procedure p1()
begin
select * from cmd;
end $$
delimiter ;
# 相當於呼叫函式
call p1()
帶引數的儲存過程
# 類似於有參函式
delimiter $$
create procedure p1(
in m int, # in表示這個引數必須只能是傳入不能被返回出去
in n int,
out res int # out表示這個引數可以被返回出去,還有一個inout表示即可以傳入也可以被返回出去
)
begin
select tname from userinfo where id > m and id < n;
set res=0; # 用來標誌儲存過程是否執行
end $$
delimiter ;
# 針對res需要先提前定義
set @res=10; 定義
select @res; 檢視
call p1(1,5,@res) 呼叫
'''
檢視儲存過程具體資訊
show create procedure pro1;
檢視所有儲存過程
show procedure status;
刪除儲存過程
drop procedure pro1;
'''
函式
'''
mysql內建的函式只能在sql語句中使用
可以通過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 計算兩個日期差值
...
流程控制
# python if判斷
if 條件:
子程式碼
elif 條件:
子程式碼
else:
子程式碼
# js if判斷
if(條件){
子程式碼
}else if(條件){
子程式碼
}else{
子程式碼
}
# MySQL if判斷
if 條件 then
子程式碼
elseif 條件 then
子程式碼
else
子程式碼
end if;
# MySQL while迴圈
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 索引鍵
上面三種key前兩種除了有加速查詢的效果之外還有額外的約束條件(primary key:非空且唯一,unique key:唯一),而index key沒有任何約束功能只會幫你加速查詢
'foreign key不是用來加速查詢用的,不在我們研究範圍之內'
# 索引的基本用法
id name pwd post_comment addr age
基於id查詢資料很快 但是基於addr查詢資料就很慢
解決的措施可以是給addr新增索引
'''索引雖然好用 但是不能無限制的建立!!!'''
索引的底層資料結構是b+樹
b樹 紅黑樹 二叉樹 b*樹 b+樹
上述結構都是為了更好的基於樹查詢到相應的資料
聚焦索引
聚集索引是將主鍵與行記錄儲存在一起,當根據主鍵進行查詢時,可直接在表中獲取到資料,不用回表查詢。InnonDB的所有的表都是索引組織表,主鍵與資料存放在一起。InnoDB選擇聚集索引遵循以下原則:
在建立表時,如果指定了主鍵,則將其作為聚集索引。
如果沒有指定主鍵,則選擇第一個NOT NULL(非空)的唯一索引作為聚集索引。
如果沒有唯一索引,則內部會產生一個6位元組的rowID(主鍵值)作為主鍵
輔助索引
# 輔助索引
查詢資料的時候不可能都是用id作為篩選條件,也可能會用name,password等欄位資訊,那麼這個時候就無法利用到聚集索引的加速查詢效果。就需要給其他欄位建立索引
優勢:顯示指定的主鍵可以是普通的int型別,這樣儲存空間就是4位元組,在二級索引的葉子結點中儲存主鍵的所佔用空間就會變小
'''
葉子結點存放的是輔助索引欄位對應的那條記錄的主鍵的值(比如:按照name欄位建立索引,那麼葉子節點存放的是:{name對應的值:name所在的那條記錄的主鍵值})
資料查詢 如果一開始使用的是輔助索引 那麼還需要使用聚焦索引才可以獲取到真實資料
'''
覆蓋索引
#覆蓋索引:
只在輔助索引的葉子節點中就已經找到了所有我們想要的資料
select name from user where name='jason';
#非覆蓋索引:
雖然查詢的時候命中了索引欄位name,但是要查的是age欄位,所以還需要利用主鍵才去查詢
select age from user where name='jason';