Mysql數據庫高級使用-PyMySQL、SQL注入與防止、事務、索引

上文基礎命令直達鏈接:MySQL命令行客戶端常用命令匯總

PyMySQL的使用

在Python中連接操作mysql需要先安裝第三方庫pymysql,執行命令:pip install pymysql

  • pymysql使用:
  1. 導入pymysql模塊
import pymysql
  1. 創建連接對象
    調用pymysql模塊中的connect()函數來創建連接對象,連接到數據庫需要傳入較多參數:

參數host:連接的mysql主機,如果本機 是'localhost'
參數port:連接的mysql主機的端口,默認是3306
參數user:連接的用戶名
參數password:連接的密碼
參數database:數據庫的名稱
參數charset:通信采用的編碼方式,推薦使用utf8

conn = pymysql.connect(host="localhost",
                       port=3306,
                       user="root",
                       password="mysql",
                       database="python",
                       charset="utf8")
  1. 獲取游標對象
    獲取游標對象的目標就是要執行sql語句,完成對數據庫的增、刪、改、查操作。代碼執行完畢應執行關閉操作.
cursor= conn.cursor()
  1. pymysql完成數據的查詢操作示例
import pymysql

# 創建連接對象
conn = pymysql.connect(
                    host="localhost",
                    port=3306,
                    user="root",
                    password="mysql",
                    database="python",
                    charset="utf8"
                       )

# 獲取游標對象
cursor = conn.cursor()

# 查詢 SQL 語句
sql = "select * from students;"
# 執行 SQL 語句 返回值就是 SQL 語句在執行過程中影響的行數
row_count = cursor.execute(sql)
print("SQL 語句執行影響的行數%d" % row_count)

# 取出結果集中一行數據, 例如:(1, '張三')
# print(cursor.fetchone())

# 取出結果集中的所有數據, 例如:((1, '張三'), (2, '李四'), (3, '王五'))
for line in cursor.fetchall():
    print(line)

# 關閉游標
cursor.close()

# 關閉連接
conn.close()
  1. pymysql完成對數據的增刪改示例
    代碼中使用的commit()和rollback()方法為事務的操作,在我另一篇文章單獨講到.
import pymysql

# 創建連接對象
conn = pymysql.connect(
                    host="localhost",
                    port=3306,
                    user="root",
                    password="mysql",
                    database="python",
                    charset="utf8"
                       )
# 獲取游標對象
cursor = conn.cursor()
try:
    # 添加 SQL 語句
    # sql = "insert into students(name) values('胖太'), ('老師');"
    # 刪除 SQ L語句
    # sql = "delete from students where id = 5;"
    # 修改 SQL 語句
    sql = "update students set name = '夏目' where id = 5;"
    # 執行sql語句
    row_count = cursor.execute(sql)
    print("SQL語句影響的行數為%d" % row_count)
    # 提交事務
    conn.commit()
except Exception as e:
    print(e)
    # 提交失敗,回滾事務,即撤銷剛執行的SQL操作
    conn.rollback()
# 關閉游標
cursor.close()
# 關閉鏈接
conn.close()

conn.commit() 表示將修改操作提交到數據庫
conn.rollback() 表示回滾數據

SQL注入與防止
  • SQL注入是什么?
    用戶提交帶有惡意的數據與SQL語句進行字符串方式拼接,從而影響后臺SQL語句的含義,最終產生數據泄露的現象.
    例如,當前存在數據庫''jing_dong'',其中有數據表''goods'',此表中存放有大量商品信息。
    在下面代碼中模擬用戶查詢輸入:
import pymysql
# 創建連接對象
conn = pymysql.connect(host='localhost',port=3306,user='root',password='mysql',database='jing_dong',charset='utf8')

find_name = input("請輸入商品名稱:")
# 獲取游標對象
cursor = conn.cursor()
sql = "select * from goods WHERE name = '%s'" % find_name
print("實際后臺執行的SQL語句為:",sql)
count = cursor.execute(sql)
print("SQL語句影響的行數:%d" % count)
# 獲取查詢結果
result = cursor.fetchall()
print(result)
cursor.close()
conn.close()

用戶正常輸入時,將返回我們需要的指定商品信息:

請輸入商品名稱:商務雙肩背包
實際后臺執行的SQL語句為: select * from goods WHERE name = '商務雙肩背包'
SQL語句影響的行數:2
((19, '商務雙肩背包', 6, 6, Decimal('99.000'), b'\x01', b'\x00'), (21, '商務雙肩背包', 6, 6, Decimal('99.000'), b'\x01', b'\x00'))

用戶惡意輸入時,將會出現整體數據泄露的問題:

請輸入商品名稱:' or 1=1 or '
實際后臺執行的SQL語句為: select * from goods WHERE name = '' or 1=1 or ''
SQL語句影響的行數:21
((1, 'r510vc 15.6英寸筆記本', 5, 2, Decimal('3399.000'), b'\x01', b'\x00'), (2, 'y400n 14.0英寸筆記本電腦', 5, 7, Decimal('4999.000'), b'\x01', b'\x00'), (3, 'g150th 15.6英寸游戲本', 4, 9, Decimal('8499.000'), b'\x01', b'\x00'), (4, 'x550cc 15.6英寸筆記本', 5, 2, Decimal('2799.000'), b'\x01', b'\x00'), (5, 'x240 超極本', 7, 7, Decimal('4880.000'), b'\x01', b'\x00'), (6, 'u330p 13.3英寸超極本', 7, 7, Decimal('4299.000'), b'\x01', b'\x00'), (7, 'svp13226scb 觸控超極本', 7, 6, Decimal('7999.000'), b'\x01', b'\x00'), (8, 'ipad mini 7.9英寸平板電腦', 2, 8, Decimal('1998.000'), b'\x01', b'\x00'), (9, 'ipad air 9.7英寸平板電腦', 2, 8, Decimal('3388.000'), b'\x01', b'\x00'), (10, 'ipad mini 配備 retina 顯示屏', 2, 8, Decimal('2788.000'), b'\x01', b'\x00'), (11, 'ideacentre c340 20英寸一體電腦 ', 1, 7, Decimal('3499.000'), b'\x01', b'\x00'), (12, 'vostro 3800-r1206 臺式電腦', 1, 5, Decimal('2899.000'), b'\x01', b'\x00'), (13, 'imac me086ch/a 21.5英寸一體電腦', 1, 8, Decimal('9188.000'), b'\x01', b'\x00'), (14, 'at7-7414lp 臺式電腦 linux )', 1, 3, Decimal('3699.000'), b'\x01', b'\x00'), (15, 'z220sff f4f06pa工作站', 3, 4, Decimal('4288.000'), b'\x01', b'\x00'), (16, 'poweredge ii服務器', 3, 5, Decimal('5388.000'), b'\x01', b'\x00'), (17, 'mac pro專業級臺式電腦', 3, 8, Decimal('28888.000'), b'\x01', b'\x00'), (18, 'hmz-t3w 頭戴顯示設備', 6, 6, Decimal('6999.000'), b'\x01', b'\x00'), (19, '商務雙肩背包', 6, 6, Decimal('99.000'), b'\x01', b'\x00'), (20, 'x3250 m4機架式服務器', 3, 1, Decimal('6888.000'), b'\x01', b'\x00'), (21, '商務雙肩背包', 6, 6, Decimal('99.000'), b'\x01', b'\x00'))

此處數據表內的全部信息都返回給了用戶,原因在于用戶惡意輸入的內容和后臺SQL查詢語拼接,導致語義改變,最終產生數據泄露。
使SQL語義改變的最終原因就是字符串拼接產生的漏洞

  • 防止SQL注入
    1. SQL語言中的參數使用%s來占位,此處不是python中的字符串格式化操作

    2. 將SQL語句中%s占位所需要的參數存在一個列表中,把參數列表傳遞給execute方法中第二個參數
      代碼示例:

import pymysql
# 創建連接對象
conn = pymysql.connect(host='localhost',port=3306,user='root',password='mysql',database='jing_dong',charset='utf8')

find_name = input("請輸入商品名稱:")
# 獲取游標對象
cursor = conn.cursor()

# 構造參數列表
params = [find_name]
sql = "select * from goods WHERE name = %s"
count = cursor.execute(sql,params)
# 注意:
# 如果要是有多個參數,需要進行參數化
# 那么params = [數值1, 數值2....],此時sql語句中有多個%s即可
# %s 不需要帶引號

print("SQL語句影響的行數:%d" % count)
# 獲取查詢結果
result = cursor.fetchall()
print(result)
cursor.close()
conn.close()

這樣就不能再通過利用參數對SQL語句進行字符串拼接改變語義了。

事務

事務就是用戶定義的一系列執行SQL語句的操作, 這些操作要么完全地執行,要么完全地都不執行, 它是一個不可分割的工作執行單元。

事務的使用場景:
在日常生活中,有時我們需要進行銀行轉賬,這個銀行轉賬操作背后就是需要執行多個SQL語句,假如這些SQL執行到一半突然停電了,那么就會導致這個功能只完成了一半,這種情況是不允許出現,要想解決這個問題就需要通過事務來完成。

  • 事務的四大特性
    1. 原子性(Atomicity):
      事務內不可分割,要么全部提交執行,要么全部回滾不執行。
    2. 一致性(Consistency):
      在事務開始之前和事務結束以后,數據庫的完整性沒有被破壞。
    3. 隔離性(Isolation):
      一個事務所做的修改操作在提交事務之前,對于其他事務來說是不可見的。數據庫允許多個并發事務同時對其數據進行讀寫和修改的能力,隔離性可以防止多個事務并發執行時由于交叉執行而導致數據的不一致。
    4. 持久性(Durability):
      事務處理結束后,對數據的修改就是永久的,即便系統故障也不會丟失。
  • MySQL數據庫支持的表的存儲引擎

-- 查看MySQL數據庫支持的表的存儲引擎
show engines;

說明:常用的表的存儲引擎是 InnoDB 和 MyISAM;
1. InnoDB 是支持事務的
2. MyISAM 不支持事務,優勢是訪問速度快,對事務沒有要求或者以select、insert為主的都可以使用該存儲引擎來創建表

  • 開啟事務/提交事務

    1. 開啟事務有兩種方式:
      在開啟事務的語句后的sql語句將遵循事務的特性成為一個整體。

    begin;
    start transaction;

    1. 提交事務:
      將本地緩存文件中的數據提交到物理表中,完成數據的更新。

    commit;

    1. 回滾事務
      放棄本地緩存文件中的緩存數據, 表示回到開始事務前的狀態

    rollback;

說明:

  • 開啟事務后執行修改命令,變更數據會保存到本地緩存文件中,而不維護到物理表中

  • MySQL數據庫默認采用自動提交(autocommit)模式,如果沒有顯示的開啟一個事務,那么每條sql語句都會被當作一個事務執行提交的操作

  • 使用命令select @@autocommit;查看當前自動提交事務的設置狀態,默認為1,即每行sql語句自動提交事務。

  • 當設置autocommit=0就是取消了自動提交事務模式,直到顯示的執行commitrollback表示該事務結束。

  • set autocommit = 0 表示取消自動提交事務模式,需要手動執行commit完成事務的提交

  • pymysql 里面的 conn.commit() 操作就是提交事務

  • pymysql 里面的 conn.rollback() 操作就是回滾事務

索引

索引在MySQL中也叫做“鍵”,它是一個特殊的文件,它保存著數據表里所有記錄的位置信息,更通俗的來說,數據庫索引好比是一本書前面的目錄,能加快數據庫的查詢速度。

應用場景:
當數據庫中數據量很大時,查找數據會變得很慢,我們就可以通過索引來提高數據庫的查詢效率。

  • 查看表中已有索引:

show index from 表名;

  • 主鍵列會自動創建索引
  • 為字段添加索引(示例為goods表name字段添加名為index_name的索引):

alter table goods add index index_name(name);

  • 聯合索引

-- 創建聯合索引
alter table goods add index (name,price);

  1. 聯合索引又叫復合索引,即一個索引覆蓋表中兩個或者多個字段,一般用在多個字段一起查詢的時候。
  2. 減少磁盤空間開銷,因為每創建一個索引,其實就是創建了一個索引文件,索引文件過多會增加磁盤空間的開銷。
  • 聯合索引最左原則

在使用聯合索引的查詢數據時候一定要保證聯合索引的最左側字段出現在查詢條件里面,否則聯合索引失效

在使用聯合索引的時候,我們要遵守一個最左原則,即index(name,price)支持 name 、name 和 price 組合查詢,而不支持單獨 price 查詢,因為沒有用到創建的聯合索引。

  • MySQL中索引的優點和缺點和使用原則
    優點:加快數據的查詢速度
    缺點:創建索引會耗費時間和占用磁盤空間,并且隨著數據量的增加所耗費的時間也會增加

使用原則:
1. 通過優缺點對比,不是索引越多越好,而是需要自己合理的使用。
2. 對經常更新的表就避免對其進行過多索引的創建,對經常用于查詢的字段應該創建索引,
3. 數據量小的表最好不要使用索引,因為由于數據較少,可能查詢全部數據花費的時間比遍歷索引的時間還要短,索引就可能不會產生優化效果。
4. 在一字段上相同值比較多不要建立索引,比如在學生表的"性別"字段上只有男,女兩個不同值。相反的,在一個字段上不同值較多可是建立索引。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。