Mysql與Pymysql

這次介紹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表示可選的不重復的值
  • dateyyyy-mm-dd形式存儲
  • timehh:mm:ss 新式存儲
  • yearyyyy新式存儲
  • datetimeyyyy-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需要放在whereorder之間, whereorder可以不存在
  • 連表查詢結果
    • 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 AB具有對等位置, 沒有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()
執行結果
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容