這次介紹mysql
以及在python
中如何用pymysql
操作數據庫, 以及在mysql
中存儲過程, 觸發器以及事務的實現, 對應到pymysql
中應該如何操作.
**首先我們在cmd
窗口中展示常見的sql
命令: **
- 連接數據庫
mysql -u root -p
連接后顯示
- 顯示數據庫
show databases;
顯示所有的數據庫
- 創建數據庫, 設置默認編碼為
utf-8
以及默認的排序方式create database pymysql_db default charset utf8 collate utf8_general_ci;
- 選擇用那個數據庫
use pymysql_db;
- 顯示當前數據庫所有的表
show tables;
**用戶操作以及用戶權限部分(不做演示, 不常用, 備查即可): **
- 創建用戶
create user 用戶名 @ ip地址 identified by 密碼;
- 刪除用戶
drop user 用戶名 @ ip地址;
- 用戶名修改
rename user 用戶名 @ ip地址 to 新用戶名@ip地址;
- 修改指定用戶密碼
set password for 用戶名 @ ip地址 = Password(新密碼)
- 查看權限
show grants for 用戶 @ ip地址
- 給指定用戶增加權限
grant 權限 on 數據庫.表 to 用戶 @ ip地址
- 取消指定用戶的權限
revoke 權限 on 數據庫.表 from 用戶 @ ip地址
- 常見權限: 除grant外的所有權限
all privileges
; 無訪問權限usage
; 查詢權限select
; 創建表權限create
; 刪除表內容權限delete
-
用戶 @ ip地址
表示用戶在指定ip地址
下才能訪問, 當ip地址
為%
時候表示任意地址均可訪問(默認即是)
**數據表的相關操作: **
*userinfo
表創建如下: *
-- 創建一個名為userinfo的表
CREATE TABLE `userinfo` (
-- 創建一個int類型的字段nid, 該字段不能為空, 且自動遞增(注意: 一個表中只能允許一個自增的字段)
`nid` INT (11) NOT NULL AUTO_INCREMENT,
-- 創建一個varchar類型的字段name, 默認為空(varchar為變長類型, 這里指的是該字段最多占32位, 但是查詢效率不如char定長類型)
`name` VARCHAR (32) DEFAULT NULL,
`color_nid` INT (11) DEFAULT NULL,
-- 指定nid為主鍵(主鍵在一個表中是唯一不重復的, 此處可以使用多個字段組合成主鍵, 只要組合不唯一即可, 主鍵默認會自動創建索引)
PRIMARY KEY (`nid`),
-- 聲明一個名為userinfo_ibfk_1的外鍵, 該外鍵由當前表中的color_nid與color表中的nid對應(說白了就是color_nid必須是color表中nid字段具有的值才行)
CONSTRAINT `userinfo_ibfk_1` FOREIGN KEY (`color_nid`) REFERENCES `color` (`nid`)
-- 指定當前數據庫的引擎為INNODB, 默認字符集為utf-8(INNODB可支持事務)
) ENGINE = INNODB DEFAULT CHARSET = utf8;
*表color
創建如下: *
CREATE TABLE `color` (
`nid` int(11) NOT NULL AUTO_INCREMENT,
`tag` varchar(32) DEFAULT NULL,
PRIMARY KEY (`nid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
- 刪除表(表結構以及表內容)
drop table 表名
- 刪除表內容(自增不會影響)
delete from 表名
- 刪除表內容(自增也清零)
truncate table 表名
- 修改表結構
- 增加一列
alter table 表名 add 列名 類型
- 增加一列
- 刪除一列
alter table 表名 drop column 列名
- 修改列類型
alter table 表名 modify column 列名 新類型;
- 修改列名稱和列類型(類型保持不變也可)
alter table 表名 change 原列名 新列名 類型;
- 指定具體列為主鍵
alter table 表名 add primary key(列名);
- 刪除指定列的主鍵
alter table 表名 modify 列名 int, drop primary key;
- 刪除當前表中所有列的主鍵
alter table 表名 drop primary key;
- 為當前表中列指定外鍵
alter table 從表(當前表) add constraint 外鍵名稱(形如:FK_從表_主表) foreign key 從表(外鍵字段) references 主表(主鍵字段);
- 刪除外鍵
alter table 表名 drop foreign key 外鍵名稱
- 修改默認值
alter table 表名 alter 列名 set default 新默認值;
- 刪除默認值
alter table 表名 alter 列名 drop default;
**mysql
中字段的常見類型: **
- 二進制位
bit(長度)
-
tinyint[(長度)] [有無符號unsigned] [位數低于長度時候是否填充零zerofill]
有符號表示范圍-128 ~ 127
, 無負號表示范圍0 ~ 255
; 可用tinyint(1)
來模擬boolean
類型; *整型中的長度不做限制用, 僅僅做顯示用, 即長度大于位數時候是否選擇用零填充顯示 * int[(長度)] [unsigned] [zerofill]
bigint[(長度)] [unsigned] [zerofill]
-
decimal[(數字總個數 [, 小數點個數])] [unsigned] [zerofill]
該類型會以字符串類型存儲在mysql
, 以此來表示準確的浮點型 float[(數字總個數, 小數個數)] [unsigned] [zerofill]
double[(數字總個數, 小數個數)] [unsigned] [zerofill]
-
char(長度)
用固定長度存儲字符類型, 這里的長度表示所有字符所占長度, 最長為255
個字符 -
varchar(長度)
變長類型存儲字符類型, 這里的長度表示人為定制的最大長度, 查詢速度不如char
定長類型 -
text
變長類型存儲大字符串, 最多2**16 ? 1
個字符 -
mediumtext
最多2**24 ? 1
個字符 -
longtext
最多2**32 ? 1
個字符 -
enum(v1 [,v2, v3])
枚舉類型,v1
表示可選的值 -
set(v1 [, v2, v3])
集合類型,v1
表示可選的不重復的值 -
date
以yyyy-mm-dd
形式存儲 -
time
以hh:mm:ss
新式存儲 -
year
以yyyy
新式存儲 -
datetime
以yyyy-MM-dd hh:mm:ss
形式存儲
** 表中數據的操作 **
- 增加內容
insert into 表 (列名01,列名02...) values (值,值,值...) [,(值,值,值...)]
可以一次增加多條數據 - 刪除具體數據
delete from 表 where 條件'
- 修改表中具體數據
update 表 set 列名= 值 where 條件
- 查詢具體內容
select 列名01 as 別名 , 列名02 from 表 where 條件
- 常見條件: 且關系
and
; 區間關系between 開始位置 and 結束位置
; 在其中的關系in (v1, v2, v3)
; 不在其中的關系not in (v1, v2, v3)
; 在某種條件下in (select語句)
-
mysql
中的兩種通配符:%
匹配任意零個字符或者任意多個字符;_
匹配任意一個 -
mysql
中的限制條件:limit number
表前number
行以內;limit start, number
表示從start
行起始的number
行以內;limit number offset start
表示從第start'
開始的number
行以內 -
mysql
中排序顯示:order by 列1 desc,列2 asc
表示先以列1
遞減排序, 若列1
相同時候則以列2
遞增排序 - 分組:
select count(列名),sum(列名),max(列名),min(列名) from 表 where 條件 group by 列名01,列名02 order by 列名
這里的group by
需要放在where
與order
之間,where
和order
可以不存在 - 連表查詢結果
-
select A.xx B.oo from A, B where A.x=B.o
沒有A.x=B.o
對應的數據則不顯示任何結果
-
-
select A.xx B.oo from A inner join B where A.x=B.o
A
和B
具有對等位置, 沒有A.x=B.o
對應的數據則不顯示任何結果 -
select A.xx B.oo from A left join B where A.x=B.o
A
表顯示所有, 對于B
表若無符合A.x=B.o
的數據則其值為null
來顯示 -
select A.xx B.oo from B right join A where A.x=B.o
A
表顯示所有, 對于B
表若無符合A.x=B.o
的數據則其值為null
來顯示 - 組合不去重復顯示所有查詢結果
select 列名 from 表 union all select 列名 from 表
- 組合去重顯示
select 列名 from 表 union select 列名 from 表
**在mysql
中的視圖概念, 它并不是一個真實存在的表,而是根據自己寫的sql
語句執行所得的結果集, 方便查詢過程和結果比較復雜時候暫存結果以便它用. 使用視圖時候, 直接將它作為表來使用即可 **
- 視圖創建
-- 創建一個名為vw1的視圖, 視圖內容為select的語句執行結果
CREATE VIEW vw1 AS
SELECT
userinfo.`name` AS uname, color.tag AS color
FROM
userinfo
LEFT JOIN color ON userinfo.color_nid = color.nid
- 視圖使用
SELECT * from vw1;
執行結果
- 刪除視圖
drop view vw1
- 修改視圖
-- 修改視圖vw1, 修改內容直接寫上現今要執行的sql語句即可
ALTER VIEW vw1 AS
SELECT
userinfo.nid,userinfo.`name` AS uname, color.tag AS color
FROM
userinfo
LEFT JOIN color ON userinfo.color_nid = color.nid
** 在介紹觸發器, 存儲過程, 函數以及事務之前我們先簡單過一下mysql
中的條件和循環語句塊 **
- 條件判斷
if 條件 then
普通sql語句;
elseif 條件 then
普通sql語句;
else
普通sql語句;
end if;
- 循環語句
-
while
循環while 條件 do 普通sql語句; end while;
-
repeat
循環repeat 普通sql語句; until 條件; end repeat;
-
loop
循環loop_label: 標簽名 普通sql語句; -- 繼續循環 iterate loop_label; -- 跳出循環 leave loop_label; end loop;
-
** 觸發器是在對某個表執行操作(增加, 刪除和修改)的前后執行用戶特定的行為, 比如對其他的表執行增刪改的操作 **
- 創建觸發器
-- 定義結束符為$$, 在mac和linux中很有必要
delimiter $$
-- 如果存在tri_before_update_userinfo觸發器則刪除, 方便調試和修改
DROP TRIGGER if EXISTS tri_before_update_userinfo $$
-- 創建tri_before_update_userinfo觸發器, 該觸發器會在更新userinfo表之前執行begin和end之間的內容(before表示之前, after表示之后)
CREATE TRIGGER tri_before_update_userinfo BEFORE UPDATE ON userinfo FOR EACH ROW
BEGIN
-- 如果在userinfo表中更改name為tom的行則會在color表中插入一行(old表示原來的數據)
IF old.name = 'tom' THEN
INSERT INTO color(tag) VALUES('black');
-- 如果在userinfo表中有name修改后為cc則會在color表中插入一行(new表示修改后的數據)
ELSEIF new.name = 'cc' THEN
INSERT INTO color(tag) VALUES('yellow');
END IF;
end $$
delimiter ;
- 執行觸發器只需要修改
userinfo
表中的數據即可; 對于update
操作既有old
又有new
關鍵字, 對于insert
操作只有new
關鍵字, 對于delete
操作只有old
關鍵字 - 刪除指定觸發器
drop trigger if exists 觸發器名
** 存儲過程相當于一些sql
語句的堆積, 但是sql
語句執行后的結果集以及變量都可以返回給用戶; 而函數不能返回結果集, 僅僅是變量的操作 **
- 創建存儲過程
delimiter $$
DROP PROCEDURE IF EXISTS p1 $$
CREATE PROCEDURE p1(
-- 聲明僅用傳入參數用的整型形參
in in_1 INT,
-- 聲明既可以傳入又可以當返回值的整型形參
INOUT inout_1 int,
-- 聲明僅用做返回值的整型形參
OUT out_1 INT
)
BEGIN
-- 聲明語句塊中的臨時變量
DECLARE tmp_in_1 INT;
DECLARE tmp_inout_1 INT;
-- 賦值語句
SET tmp_in_1 = in_1;
set tmp_inout_1 = inout_1;
SET out_1 = tmp_in_1 + tmp_inout_1;
-- 正常的sql查詢語句
SELECT * from userinfo LIMIT in_1, inout_1;
end $$
delimiter ;
- 使用存儲過程
-- 設置用戶變量傳值,in類型可不用變量傳值, out類型不能傳入值,
-- set @in_1_tmp=1;
set @inout_1_tmp=3;
-- 調用存儲過程, 傳入參數
CALL p1 (1,@inout_1_tmp,@out_1_tmp);
-- 取得存儲過程的執行結果, 包括sql語句結果集以及變量值(in, inout以及out類型變量都能取得他們的值)
SELECT @in_1,@inout_1_tmp,@out_1_tmp;
執行結果-01
執行結果-02
- 刪除存儲過程
drop procedure 存儲過程名
** mysql
中有許多對變量進行操作的內置函數, 同時我們也可以自定義函數 **
- 內置函數第一部分
SELECT
CHAR_LENGTH("test") AS "字符串長度",
-- 拼接的任意一個參數為null, 則拼接結果為null
CONCAT("C://", "workplace") AS "字符串拼接",
CONCAT_WS("-","nick","tom") AS "自定義連接符拼接",
CONV('c',16,10) AS "進制轉換",
FORMAT(10000.00041,4) AS "格式化數字",
INSERT("teach",1,2,'xxxx') AS "字符串替換"
內置函數第一部分執行結果
- 內置函數第二部分
SELECT
INSTR("mttm","tt") AS "字串位置",
LEFT("hello, world",5) AS "從左截取字符串",
LOWER("HELLO") AS "轉換小寫",
UPPER("world") AS "轉換大寫",
LTRIM(" test ") AS "開始去空格",
RTRIM(" now ") AS "結尾去空格",
內置函數第二部分執行結果
- 內置函數第三部分
SELECT
LOCATE("tt","hehettlolo",2) AS "獲取子序列位置",
REPEAT(" | roor",5) AS "重復字符串生成",
REPLACE("hello","ll","ww") AS "字符串替換",
REVERSE("123456") AS "字符串反轉",
RIGHT("hello",3) AS "從右截取字符串",
SUBSTRING("hello, test, world" FROM -11 FOR 4) AS "自定義截取字符串",
SPACE(5) AS "返回空格字符串",
TRIM(" test ") AS "去除空格"
內置函數第三部分執行結果
- 創建函數
delimiter $$
DROP FUNCTION IF EXISTS func1 $$
CREATE FUNCTION func1(
-- 定義整型形參
i1 int,
i2 int
)
-- 定義返回參數類型
RETURNS INT
BEGIN
DECLARE tmp INT DEFAULT 0;
SET tmp = i1 + i2;
RETURN tmp;
END $$
delimiter ;
- 使用自定義函數
SELECT func1(1,1);
- 刪除自定義函數
DROP FUNCTION IF EXISTS 函數名;
** 事務的本質就是在存儲過程中將多條sql
語句作為一個原子操作來執行, 其中之一未執行成功則直接回滾到原始狀態 **
- 創建事務
delimiter $$
CREATE PROCEDURE tp1(
-- 定義返回結果參數
OUT num_flag_retunr INT
)
BEGIN
-- sql執行發生異常時候, 返回值為2, 并回滾到原始狀態
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SET num_flag_retunr=2;
ROLLBACK;
END;
-- sql語言發生警告時候, 返回值為1, 并回滾到原始狀態
DECLARE EXIT HANDLER FOR SQLWARNING
BEGIN
SET num_flag_retunr=1;
ROLLBACK;
END;
-- 開始事務具體要執行的內容, 正確則提交執行結果否則執行上面的異常
START TRANSACTION;
DELETE FROM userinfo WHERE nid=4;
INSERT INTO color(tag) VALUES("green");
COMMIT;
SET num_flag_retunr=0;
END $$
delimiter ;
- 執行事務
CALL tp1(@out_1);
SELECT @out_1;
- 刪除事務
DROP PROCEDURE IF EXISTS 事務名
** 索引相當于為我們指定的列建立一個目錄, 根據目錄我們能快速查找到所需數據 **
- 索引種類
- 普通索引
index
: 僅僅加速查詢, 無約束 - 唯一索引
unique
: 加速查詢, 指定的列不能重復, 可出現一次null
- 主鍵索引
primary key
: 加速查詢, 列值唯一切不能為null
- 組合索引 : 多列作為共同體組成索引, 效率高于多個索引列合并查詢
- 全文索引: 數據庫存儲時候對存儲內容進行分詞存儲便于搜索查詢
- 創建普通索引
CREATE INDEX name_index ON userinfo (name)
或者在創建表時候在表末尾加上index 索引名 (列)
; 對于其他索引也是類似 - 刪除索引
drop 索引名 on 表名;
- 查看當前表那些字段有索引
SHOW INDEX FROM userinfo;
有索引的字段顯示
- 以下情況即使創建了索引也不會使用索引:
-
%
開頭的模糊匹配條件:select * from 表名 where 列名 like '%其他';
- 對建立索引的列使用函數查詢:
select * from 表名 where 函數名(列名) = 其他條件
-
- 列類型匹配錯誤的條件查詢時候 :
select * from 表名 where 列名 = 不正確的類型;
- 當
or
條件中含有未建立索引的列時:select * from 表名 where 條件01 or 條件02';
- 匹配條件為不等于時候(主鍵例外) :
select * from 表名 where 非主鍵列 != 其他;
- 匹配條件為大于的時候(主鍵或索引為整型例外) :
select * from 表名 where 列名 > 其他;
- 排序時候選擇的映射與排序列不一樣即使都是索引列也不走索引(主鍵例外) :
select 索引列-01 from 表名 order by 索引列-02 desc;
- 組合索引為
索引列-01
和索引列-02
, 當先查索引列-02
時候也不走索引 - 用執行計劃可以詳細顯示
sql
語句(使用查詢語句才有意義
)的執行情況, 例如如執行EXPLAIN SELECT * from userinfo;
執行計劃執行結果
- 關于上述表中詳細字段解釋 :
-
id
查詢順序標識, 表示sql
查詢語句的執行順序 -
select_type
查詢語句的類型: 簡單查詢SIMPLE
, 最外層查詢PRIMARY
, 子查詢DERIVED
, 映射是子查詢SUBQUERY
, 聯合查詢UNION
, 聯合查詢所得UNION RESULT
-
table
正在訪問的表名 -
partitions
分區類型 -
type
查詢方式, 查詢時間性能排序 : 全表掃描all
> 全索引掃描index
> 索引部分范圍內掃描range
> 多單列索引合并掃描index_merge
> 索引匹配一個或多個值掃描ref
> 聯合主鍵索引或者唯一索引掃描eq_ref
> 最多有一個匹配行優化后作為常量表掃描const
, 還有system
特列, 性能與const
近似 -
possible_keys
可能使用的索引 -
key
實際使用的索引 -
key_len
字節長度 -
rows
預測找到所需內容要查找的行數 -
extra
其他信息, 多為mysql
解決查詢的詳細信息 -
limit
分頁優化
-- 查詢第1000條數據之后的10條數據
-- 這種查詢方式會進行全文掃描
SELECT * FROM userinfo LIMIT 1000,5;
-- 這種方式僅僅優化了一點, 使用了一些普通索引和索引合并查詢
EXPLAIN SELECT * FROM userinfo WHERE nid > (SELECT nid FROM userinfo LIMIT 1000, 1) LIMIT 5;
-- 直接根據計算所得后的最大條數倒序排列查詢
SELECT * FROM userinfo WHERE nid < 上次最大條數 ORDER BY nid DESC LIMIT 5;
- 慢查詢日志可以根據自定義設置記錄那些查詢性能查的
sql
語句 : - 查看全局變量
show global variables like "%名稱"
- 設置全局變量
set global 變量名=值
- 是否開啟慢日志全局變量
slow_query_log = OFF
- 時間限制全局變量
long_query_time = 2
- 日志文件存放位置全局變量
slow_query_log_file = /usr/slow.log
- 是否記錄未使用索引的查詢語句全局變量
log_queries_not_using_indexes = OFF
- 格式化查看慢日志
mysqldumpslow [option] 日志存放位置
, 常用option
如下: - 版本
-v
或者--verbose
- 調試模式
-d
或者--debug
- 排序方式
-s 規則選項
, 默認是平均查詢時間at
- 倒序排列顯示
-r
- 顯示前
number
條-t number
- 不要將
sql
中數字轉換成N
,字符串轉換成S
, 選項為,-a
** python
使用pymysql
操作數據庫 **
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import pymysql
# 創建連接通道, 設置連接ip, port, 用戶, 密碼以及所要連接的數據庫
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='pymysql_db')
# 創建游標, 操作數據庫, 指定游標返回內容為字典類型
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
# 調用存儲過程, 傳入參數
cursor.callproc('p1', (1, 5, 0))
# 得到結果集1, 即sql語句執行結果
select_result = cursor.fetchone()
print(select_result)
# 執行存儲過程, 獲取返回值, @_存儲過程名_第一個參數
cursor.execute("select @_p1_0,@_p1_1,@_p_2")
select_result = cursor.fetchone()
print(select_result)
cursor.close()
conn.close()
執行結果