1. 程式人生 > 其它 >學習python,從入門到放棄(48)

學習python,從入門到放棄(48)

學習python,從入門到放棄(48)

python操作MySQL

python中支援操作MySQL的模組很多,其中最常見的當屬pymysql

因為其屬於第三方模組,所以需要匯入。

pip3 install pymysql

import pymysql

使用方法:

  • 1.連結服務端

    conn_obj = pymysql.connect(
        host='127.0.0.1',  # MySQL服務端的IP地址
        port=3306,  # MySQL預設PORT地址(埠號)
        user='root',  # 使用者名稱
        password='jason123',  # 密碼  也可以簡寫 passwd
        database='jp04_3',  # 庫名稱  也可以簡寫 db
        charset='utf8'  # 字元編碼 千萬不要加槓utf-8
    )  # 要善於檢視原始碼獲取資訊
    
  • 2.產生獲取命令的遊標物件

    cursor = conn_obj.cursor(
        cursor=pymysql.cursors.DictCursor
    )  # 括號內不寫引數 資料是元組要元組 不夠精確 新增引數則會將資料處理成字典
    
  • 3.編寫SQL語句

    sql1 = 'select * from teacher;'  # SQL語句會被高亮顯示
    
  • 4.執行SQL語句

    affect_rows = cursor.execute(sql1)
    print(affect_rows)  # 執行SQL語句之後受影響的行數
    
  • 5.獲取結果

    res = cursor.fetchall()
    print(res)
    

獲取SQL語句執行的結果 跟讀取檔案內容的read方法幾乎一致(游標)

fetchone()	
fetchmany()
fetchall()
cursor.scroll(1, 'relative')  # 相對於當前位置往後移動一個單位
cursor.scroll(1, 'absolute')  # 相對於起始位置往後移動一個單位

SQL注入問題

有時候我們會遇見一些奇怪的情況。

  • 寫正確的使用者名稱錯誤的密碼也可以登入
  • 使用者名稱和密碼都不需要也可以登入

上述現象就是典型的SQL注入問題,利用的是MySQL註釋語法及邏輯運算子

解決SQL注入的問題其實也很簡單 就是想辦法過濾掉特殊符號。execute方法自帶校驗SQL注入問題,自動處理特殊符號。設計到敏感資料的拼接,全部交給execute方法即可。

sql = "select * from userinfo where name=%s and password=%s;"
cursor.execute(sql, (name, password))

二次確認

資料的增刪改查四個操作是有輕重之分的,

查:不會影響真正的資料,重要程度最低。

增、改、刪:都會影響真正的資料,重要程度較高。

pymysql針對增、改、刪三個操作,都設定了二次確認,如果不確認則不會真正影響資料庫。

  • 程式碼直接編寫

    affect_row = cursor.execute(sql)
    conn_obj.commit()  # 手動二次確認
    
  • 配置固定引數

    conn_obj = pymysql.connect(
    	autocommit=True  # 自動二次確認
    )
    

修改表SQL語句補充

  • 修改表的名字

    rename

    alter table t1 rename ttt;
    
  • 新增欄位

    add

    alter table ttt add pwd int; # 預設是尾部追加欄位
    alter table ttt add tid int after name; # 指定追加位置
    alter table ttt add nid int first; # 指定頭部新增欄位
    
  • 修改欄位

    change(名字型別都可)/modify(只能改型別不能改名字)

    alter table ttt change pwd password tinyint;
    
  • 刪除欄位

    drop

    alter table ttt drop nid;
    

檢視

通過SQL語句的執行得到的一張虛擬表,儲存下來之後就稱之為'檢視'

如果需要頻繁的使用一張虛擬表,可以考慮製作成檢視,降低操作難度。

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

臨時修改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 ;  # 結束之後記得再改回來,不然後面結束符就都是$$了
    
  • 僅僅往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');
    

檢視當前庫下所有的觸發器資訊

show triggers\G;

刪除當前庫下指定的觸發器資訊

drop trigger 觸發器名稱;

事務

事務可以包含諸多SQL語句並且這些SQL語句,要麼同時執行成功,要麼同時執行失敗,這是事務的原子性特點。

事務有 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;
    

    編寫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;  # 執行完確認提交之後 無法回滾 事務自動結束
    

儲存過程

類似於python中的自定義函式

  • 定義函式

    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)  呼叫
  select @res  檢視

檢視儲存過程具體資訊

show create procedure pro1;

檢視所有儲存過程

show procedure status;

刪除儲存過程

drop procedure pro1;

函式

注意與儲存過程的區別,mysql內建的函式只能在sql語句中使用

  • 移除指定字元

    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 Month(sub_time)=07;
    
    • 更多日期處理相關函式

      adddate 增加一個日期
      addtime 增加一個時間
      datediff 計算兩個日期差值

流程控制

  • if判斷

    if 條件 then
            子程式碼
    elseif 條件 then
            子程式碼
    else
            子程式碼
    end if;
    
  • 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沒有任何約束功能只會幫你加速查詢

  • 索引的基本用法

    表中有一下幾個屬性

    id name pwd post_comment addr age

    其中id是主鍵

    基於id查詢資料很快 但是基於addr查詢資料就很慢

    解決的措施可以是給addr新增索引

索引雖然好用 但是不能無限制的建立

在表中有大量資料的前提下,建立索引速度會很慢。
在索引建立完畢後,對錶的查詢效能會大幅度提升,但是寫的效能會降低

索引的底層資料結構是b+樹
資料結構有b樹、紅黑樹、二叉樹、b*樹、b+樹
上述結構都是為了更好的基於樹查詢到相應的資料

只有葉子結點存放真實資料,根和樹枝節點存的僅僅是虛擬資料
查詢次數由樹的層級決定,層級越低次數越少
一個磁碟塊兒的大小是一定的,那也就意味著能存的資料量是一定的。如何保證樹的層級最低呢?一個磁碟塊兒存放佔用空間比較小的資料項
我們應該給我們一張表裡面的什麼欄位欄位建立索引能夠降低樹的層級高度>>> 主鍵id欄位

聚集索引(primary key)
輔助索引(unique key,index key)
查詢資料的時候不可能都是用id作為篩選條件,也可能會用name,password等欄位資訊,那麼這個時候就無法利用到聚集索引的加速查詢效果。就需要給其他欄位建立索引,這些索引就叫輔助索引

葉子結點存放的是輔助索引欄位對應的那條記錄的主鍵的值(比如:按照name欄位建立索引,那麼葉子節點存放的是:{name對應的值:name所在的那條記錄的主鍵值})
資料查詢 如果一開始使用的是輔助索引 那麼還需要使用聚焦索引才可以獲取到真實資料

覆蓋索引:只在輔助索引的葉子節點中就已經找到了所有我們想要的資料

select name from user where name='jason';

非覆蓋索引:雖然查詢的時候命中了索引欄位name,但是要查的是age欄位,所以還需要利用主鍵才去查詢

select age from user where name='jason';