1. 程式人生 > 其它 >python操作MySQL、事務、SQL注入問題

python操作MySQL、事務、SQL注入問題

python操作MySQL

python中支援操作MySQl的模組很多 其中最常見就是'pymysql'
# 屬於第三方模組
    pip3 install pymysql
# 基本使用
import pymysql
# 1.連結服務端
import pymysql

conn_obj = pymysql.connect(
host='127.0.0.1',  # MySQL服務端的IP地址
port=3306,  # MySQL預設PORT地址(埠號)
user='root',  # 使用者名稱
password='admin',  # 密碼  也可以簡寫 passwd
database='py05',  # 庫名稱  也可以簡寫 db
charset='utf8',  # 字元編碼 千萬不要加槓utf-8
autocommit=True  # 自動二次確認
)
# 2.產生獲取命令的遊標物件
cursor = conn_obj.cursor(
cursor=pymysql.cursors.DictCursor  # 括號內不寫引數 資料是元組要元組 不夠精確 新增引數則會將資料處理成字典
)
# 3.編寫SQL語句
sql1 = 'show tables;'
 # 4.執行SQL語句
affect_rows = cursor.execute(sql1)
print(affect_rows)  # 執行SQL語句之後受影響的行數
# 5.獲取結果
res = cursor.fetchall()
print(res)

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


'''補充說明'''
獲取SQL語句執行的結果 跟讀取檔案內容的read方法幾乎一致(游標)
fetchone() # 獲取結果集中的第一個
fetchmany() # 獲取結果集中的指定個數
fetchall() # 獲取結果集中所有
cursor.scroll(1, 'relative') # 相對於當前位置往後移動一個單位
cursor.scroll(1, 'absolute') # 相對於起始位置往後移動一個單位

 

SQL注入問題

# 寫正確的使用者名稱錯誤的密碼也可以登入
使用者名稱:lsw' -- jhahsdjasdjasd 密碼:直接回車 # 使用者名稱和密碼都不需要也可以登入 使用者名稱:xxx' or 1=1 -- asdjasjdkajsd 密碼:直接回車 """上述現象就是典型的SQL注入問題""" 上述情況利用的是MySQL註釋語法及邏輯運算子 # 解決SQL注入的問題其實也很簡單 就是想辦法過濾掉特殊符號 execute方法自帶校驗SQL注入問題 自動處理特殊符號 ps:設計到敏感資料的拼接 全部交給execute方法即可!!! sql = "select * from userinfo where name=%s and pwd=%s;
" cursor.execute(sql, (name, pwd)) """ execute方法補充(瞭解) 批量插入資料 sql = 'insert into userinfo(name,pwd) values(%s,%s)' cursor.executemany(sql,[('tom',123),('lavin',321),('pony',333)]) """
import pymysql

conn_obj = pymysql.connect(
host='127.0.0.1',
port=3306,
user='root',
password='admin',
database='py06',
charset='utf8',
autocommit=True
)
cursor = conn_obj.cursor(
cursor=pymysql.cursors.DictCursor)

# 1.獲取使用者名稱和密碼
name = input('請輸入使用者名稱:').strip()
pwd = input('請輸入密碼:').strip()
sql = "select * from userpwd where name=%s and pwd=%s;"
cursor.execute(sql, (name, pwd))
res = cursor.fetchall()
if res:
print('登陸成功')
else:
print('使用者名稱或密碼錯誤')
 

二次確認

"""
資料的增刪改查四個操作是有輕重之分的
    查                           不會影響真正的資料 重要程度最低
    增、改、刪                    都會影響真正的資料 重要程度較高
pymysql針對增、改、刪三個操作 都設定了二次確認 如果不確認則不會真正影響資料庫
"""
方式1:程式碼直接編寫
    affect_row = cursor.execute(sql)
    conn_obj.commit()  # 手動二次確認
方式2:配置固定引數
  conn_obj = pymysql.connect(
    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;

檢視

"""
檢視的概念 
    通過SQL語句的執行得到的一張虛擬表 儲存下來之後就稱之為'檢視'
檢視的作用
    如果需要頻繁的使用一張虛擬表 可以考慮製作成檢視 降低操作難度
        eg: emp與dep表拼接
檢視的製作
    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 $$
臨時修改的原因是因為觸發器 儲存過程等技術點 程式碼中也需要使用分號
如果不修改 則無法書寫出完成的程式碼
"""
    1.先建立兩張表
      # 案例
    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
    );
  2.需求: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');
  4.觸發器其他補充
      檢視當前庫下所有的觸發器資訊
        show triggers\G;
    刪除當前庫下指定的觸發器資訊
        drop trigger 觸發器名稱;

事務

"""
事務的概念
    事務可以包含諸多SQL語句並且這些SQL語句
    要麼同時執行成功 要麼同時執行失敗 這是事務的原子性特點
事務的作用
    戴某某欠了趙某某一筆錢 現在想要還錢
        戴某某拿著交行的銀行卡去招商銀行的ATM機給趙某某的建行卡轉錢
            1.朝交行的伺服器傳送請求 修改戴某某賬戶餘額(減錢)
            2.朝建行的伺服器傳送請求 修改趙某某賬戶餘額(加錢)
事務的四大特性(重點)
    ACID
        A:原子性
            一個事務是一個不可分割的整體 裡面的操作要麼都成立要麼都不成立
        C:一致性
            事務必須使資料庫從一個一致性狀態變到另外一個一致性狀態
        I:隔離性
            併發程式設計中 多個事務之間是相互隔離的 不會彼此干擾
        D:永續性
            事務一旦提交 產生的結果應該是永久的 不可逆的
        課下可以自己百度搜索整理 上面是老師整理的簡單概述版本
ps:辛辛苦苦一個月 換來的就是一條SQL語句!!!
"""
具體使用
    1.建立表及錄入資料
      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);
  2.事務操作
      開啟一個事務的操作
        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內建的函式

"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    計算兩個日期差值
  ...

流程控制

# 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沒有任何約束功能只會幫你加速查詢
# ps:foreign key不是用來加速查詢用的,不在我們研究範圍之內

# 索引的基本用法
id    name    pwd        post_comment  addr  age 
    基於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';
"""