Python 高級 16 數據庫Pymysql

數據庫編程概述、pymysql基本操作方法總結、參數化列表防止SQL注入總結

2.6 Python數據庫編程

學習目標

? 1. 能夠說出數據庫編程的5個步驟

? 2. 能夠使用python從數據庫取出數據操作

--------------------------------------------------------------------------------

2.6.1 數據庫編程概述

數據庫編程就是針對數據庫的操作,通過編寫程序的方式,讓程序做為數據庫的客戶端進行數據庫操作。

通過使用程序代碼的方式去連接數據庫服務器,通過和服務器進行交互完成對數據庫的增刪改查的方式,就稱為數據庫編程。

數據庫概念包含 數據庫文件、服務器和數據庫客戶端,pymysql就是一種客戶端。

? pymysql的安裝:

? 1. 聯網pip命令安裝

? ? ? a. pip3 install PyMySQL

? ? ? b. 在使用該命令的時候可能會提示需要管理員權限進行安裝,只需要在前面加上sudo即可;

? 2. 使用 git 命令下載安裝包安裝(你也可以手動下載):

? ? ? a. git clone https://github.com/PyMySQL/PyMySQL

? ? ? b. cd PyMySQL/

? ? ? c. python3 setup.py install

? ? ? ? ? i. 如果有安裝包直接切換路徑,和setup.py同級,再安裝

? 1>pymysql基本操作方法總結:

? ? ? 1>Python 中操作數據庫,要經過五個步驟

? ? ? ? ? ■ 1.連接數據庫,2.獲取游標,3.數據庫操作,4.關閉游標,5.關閉數據庫連接

? ? ? 2>數據庫對象

? ? ? ? ? ■ 獲取游標

? ? ? ? ? ? ? cursor()

? ? ? ? ? ■ 提交數據

? ? ? ? ? ? ? commit()

? ? ? ? ? ■ 撤銷操作

? ? ? ? ? ? ? rollback()

? ? ? ? ? ■ 關閉連接

? ? ? ? ? ? ? close()

? ? ? 3>游標對象

? ? ? ? ? ■ 執行SQL語句

? ? ? ? ? ? ? execute()

? ? ? ? ? ■ 獲取一條查詢 結果

? ? ? ? ? ? ? fetchone()

? ? ? ? ? ■ 獲取指定條數查詢結果

? ? ? ? ? ? ? fetchmany(n)

? ? ? ? ? ■ 獲取所有查詢 結果

? ? ? ? ? ? ? fetchall()

? ? ? ? ? ■ 關閉游標

? ? ? ? ? ? ? close()

? 2.參數化列表防止SQL注入總結

? ? ? 1>什么是SQL注入?

? ? ? ? ? ■ 是指在連接SQL語句時,用戶傳入了非法的數據,使SQL語句的意義發生變化,導至數據泄露

? ? ? 2>產生原因:

? ? ? ? ? ■ 后臺對用戶提交的帶有惡意的數據和 SQL 進行字符串方式的拼接,得到了脫離原意的 SQL 語句,從而影響了 SQL 語句的語義,最終產生數據泄露的現象。

? ? ? 3>如何防止:

? ? ? ? ? ■ SQL 語句的參數化, 將 SQL 語句的所有數據參數存在一個列表中傳遞給 execute 函數的第二個參數

? ? ? 4>注意:

? ? ? ? ? ■ sql語句中 -- 代表注釋的意思

? ? ? ? ? ■ 此處不同于python的字符串格式化,必須全部使用%s占位

2.6.2 Python 中操作 MySQL 步驟

在 Python 中操作數據庫,要經過五個步驟,分別是連接數據庫,獲取游標,數據庫操作,關閉游標,關閉數據庫連接。

這個過程和實際倉庫操作相同,比如現在要去一個實際的倉庫。

2.6.3 pymysql 操作

在 Pyhton 中,使用 Pymysql 模塊來對數據庫進行編程。

? 導入模塊(connect = Connection = Connect)

? ? ? ? from pymysql import Connect

? <1>創建連接對象 conn=Connect(參數列表)

? ? ? 目的:用于建立代碼與數據庫的連接

? ? ? * 參數host:連接的mysql主機,如果本機是'localhost'

? ? ? * 參數port:連接的mysql主機的端口,默認是3306

? ? ? * 參數database:數據庫的名稱

? ? ? * 參數user:連接的用戶名

? ? ? * 參數password:連接的密碼

? ? ? * 參數charset:通信采用的編碼方式,推薦使用utf8

? <2>通過連接對象獲取游標對象 cur = conn.cursor()

? ? ? 創建Cursor游標對象 目的: 用于執行sql語句并獲得結果

? <3>使用游標執行SQL語句 cur.execute(operation , [parameters])

? ? ? ? 1>sql_str = '''select * from students;'''

? ? ? ? ? ■ 注意:以字符串形式書寫SQL語句,因為SQL語句中也會出現字符串,所以建議使用三引號 ``` 引號形式將SQL詩句引起來

? ? ? 2>執行SQL語句row_count = cur.execute(sql_str)

? ? ? ? ? ■ 注意:執行SQL語句,返回受影響的行數,主要用于執行insert、update、delete語句

? ? ? ? ? ? ? 打印row_count輸出受影響的行數

? ? ? 3>取出結果:

? ? ? ? ? ■ 注意:因為在獲取數據時,游標是移動的,所以前面取過的數據,后面不會再取了。

? ? ? ? ? ■ 1.獲取結果集中的一條 row_one = cur.fetchone()

? ? ? ? ? ? ? 返回一個元組 如 (1,'妲己',18)

? ? ? ? ? ■ 2.獲取結果集中指定條數 row_many = cur.fetchmany(2)

? ? ? ? ? ? ? 返回一個元組 如 ((1,'妲己',18),(2,'公孫離',20))

? ? ? ? ? ? ? cur.fetchmany(n)獲取結果集中的n條,返回一個元組

? ? ? ? ? ■ 3.獲取結果集中的所有 row_all = cur.fetchall()

? ? ? ? ? ? ? 執行查詢時,獲取結果集的所有行,一行構成一個元組,再將這些元組裝入一個元組返回. 如((1,'妲己',18),(2,'公孫離',20),(3,'姜子牙',28))

? ? ? 4>提交數據 conn.commit()

? ? ? ? ? ■ 撤銷數據 conn.rollback()

? <4>關閉游標 cur.close()

? <5>關閉連接 conn.close()

2.6.4 使用 pymsql 完成數據查詢

? 準備數據

? ? ? 1>創建數據庫

? ? ? ? ? ■ create database python_db charset=utf8;

? ? ? 2>使用數據庫

? ? ? ? ? ■ use python_db;

? ? ? 3>students表

? ? ? ? ? ■ 注意:unsigned表示無符號的意思,也就是非負數,只用于整型

? ? ? ? ? ■ create table students(

? ? id int unsigned primary key auto_increment not null,

? ? name varchar(20) default '',

? ? age tinyint unsigned default 0,

? ? height decimal(5,2),

? ? gender enum('男','女','中性','保密') default '保密',

? ? cls_id int unsigned default 0,

? ? is_delete int default 0);

? ? ? 4>classes表

? ? ? ? ? ■ create table classes (

? ? id int unsigned auto_increment primary key not null,

? ? name varchar(30) not null);

? ? ? 5>向students表中插入數據

? ? ? ? ? ■ insert into students values

(0,'小明',18,180.00,2,1,0),

(0,'小月月',18,180.00,2,2,1),

(0,'彭于晏',29,185.00,1,1,0),

(0,'劉德華',59,175.00,1,2,1),

(0,'黃蓉',38,160.00,2,1,0),

(0,'鳳姐',28,150.00,4,2,1),

(0,'王祖賢',18,172.00,2,1,1),

(0,'周杰倫',36,NULL,1,1,0),

(0,'程坤',27,181.00,1,2,0),

(0,'劉亦菲',25,166.00,2,2,0),

(0,'金星',33,162.00,3,3,1),

(0,'靜香',12,180.00,2,4,0),

(0,'郭靖',12,170.00,1,4,0),

(0,'周杰',34,176.00,2,5,0);

? ? ? 6>向classes表中插入數據

? ? ? ? ? ■ insert into classes values (0, "python_01期"), (0, "python_02期");

? 查詢數據

# 導入模塊

from pymysql import connect

# 連接數據庫

conn = connect(host='localhost', port=3306, database='python_db', user='root', password='123123',charset='utf8')

# 獲取游標

cur = conn.cursor()

# 以字符串形式書寫SQL語句,因為SQL語句中也會出現字符串,所以建議使用 ``` 引號形式將SQL詩句引起來

sql_str = '''select * from students;'''

# 執行SQL語句

row_count = cur.execute(sql_str)

# 顯示執行 SQL 語句影響的行數

print(row_count)

# 獲取一條記錄

row_one = cur.fetchone()

# 顯示獲取的記錄

print(row_one)

# 獲取多條記錄

row_many = cur.fetchmany(4)

# 遍歷輸出所有的結果

for t in? row_many:

? ? print(t)

# 獲取所有的數據

row_all = cur.fetchall()

# 遍歷輸出所有的結果

for t in? row_all:

? ? print(t)

# 關閉游標

cur.close()

# 關閉數據庫

conn.close()

注意:因為在獲取數據時,游標是移動的,所以前面取過的數據,后面不會再取了。

? 增刪改

# 導入模塊

from pymysql import connect

# 連接數據庫

conn = connect(host='localhost', port=3306, database='python_db', user='root', password='123123',charset='utf8')

# 獲取游標

cur = conn.cursor()

# 以字符串形式書寫SQL語句

# sql_str = '''insert into students values(0,'新來的',20,180,'男',1,1)'''

# sql_str = '''update students set name = '王鋼蛋' where name = '新來的'; '''

sql_str = '''delete from students where name='王鋼蛋'; '''

# 執行SQL語句

row_count = cur.execute(sql_str)

# 在執行增刪改操作時,需要向數據庫提交操作,否則操作不成功

conn.commit()

# 關閉游標

cur.close()

# 關閉數據庫

conn.close()

? 回滾(取消操作)

# 導入模塊

from pymysql import connect

# 連接數據庫

conn = connect(host='localhost', port=3306, database='python_db', user='root', password='123123',charset='utf8')

# conn.autocommit(True)

# 獲取游標

cur = conn.cursor()

# 以字符串形式書寫SQL語句

sql_str = '''insert into students values(0,'新來的',20,180,'男',1,1)'''

#插入10條數據

for i in range(10):

? ? # 執行SQL語句

? ? row_count = cur.execute(sql_str)

# 在執行增刪改操作時,如果不想提交前面的修改操作,可以使用 rollback 回滾取消操作

conn.rollback()

# 關閉游標

cur.close()

# 關閉數據庫

conn.close()

2.6.5 參數化列表防止SQL注入

? 什么是SQL注入?

? ? ? 是指在連接SQL語句時,用戶傳入了非法的數據,使SQL語句的意義發生變化,導至數據泄露

? 產生原因:

? ? ? 后臺對用戶提交的帶有惡意的數據和 SQL 進行字符串方式的拼接,得到了脫離原意的 SQL 語句,從而影響了 SQL 語句的語義,最終產生數據泄露的現象。

? 如何防止:

? ? ? SQL 語句的參數化, 將 SQL 語句的所有數據參數存在一個列表中傳遞給 execute 函數的第二個參數

? 注意:

? ? ? sql語句中 -- 代表注釋的意思

? ? ? 此處不同于python的字符串格式化,必須全部使用%s占位

? # 導入模塊

? from pymysql import connect

? find_name = input("請輸姓名:")

? # 連接數據庫

? conn = connect(host='localhost', port=3306, database='python_db', user='root', password='123123', charset='utf8')

? # 獲得Cursor對象

? cur = conn.cursor()

? # # # 非安全的方式

? # # # 輸入 "小明" or 1

? # sql = '''select * from students where name=%s''' % find_name

? # print("""sql===>%s<====""" % sql)

? # # 執行select語句,并返回受影響的行數:查詢所有數據

? # count = cur.execute(sql)

? # 安全的方式

? # 構造參數列表

? params = [find_name]

? sql = '''select * from students where name=%s;'''

? print("""sql===>%s<====""" % sql)

? # 執行select語句,execute方法在內部實現了防SQL注入的功能,但具體如何實現并不清楚,隱藏了細節

? count = cur.execute(sql, params)

? # 注意:

? # 如果要是有多個參數,需要進行參數化

? # 那么params = [數值1, 數值2....],此時sql語句中有多個%s即可

? # 打印受影響的行數

? print(count)

? # 獲取查詢的結果

? result = cur.fetchall()

? # 打印查詢的結果

? print(result)

? # 關閉Cursor對象

? cur.close()

? # 關閉Connection對象

? conn.close()

2.6.6 數據庫編程練習

? 準備數據

? ? ? 創建數據庫

? ? ? ? ? ■ create database JDDB charset=utf8;

? ? ? ? ? ■ use JDDB

? ? ? 導入數據

? ? ? ? ? ■? source JDDB.sql

? 代碼實現

? ? ? 1>判斷當前是否是主程序

if __name__ == '__main__':

main()

? 2>實現主函數

def main():

# 創建 JD 類的對象

jd = JD()

# 運行 run 方法

jd.run()

? 3>實現 JD 類 因為所有的操作都要操作數據庫,為了避免代碼冗余,所以將連接和關閉操作設計到類中

? 對象創建成功,數據庫就連接成功,對象銷毀時,數據庫關閉

class JD(object):

"""JD 類,提供商品查詢服務"""

# 將數據庫連接操作放到初化方法中,對象創建時,自動連接數據庫

def __init__(self):

# 連接數據庫

self.__conn = connect(host='localhost', port=3306, database='JDDB', user='root', password='123123', charset='utf8')

# 獲取游標

self.__cur = self.__conn.cursor()

# 將數據庫關閉操作放到 __del__方法中,當對象銷毀時,自動關閉數據庫

def __del__(self):

# 關閉游標

self.__cur.close()

# 關閉數據庫

self.__conn.close()

? 4>實現 run 方法 因為需要重復選擇,所以要用死循環

# run 方法,提供顯示接口

def run(self):

while True:

? ? print("1查詢所有商品信息")

? ? print("2查詢所有商品在種類信息")

? ? print("3查詢所有商品在品牌信息")

? ? print("4添加商品種類")

? ? print("5根據id查詢商品信息")

? ? print("6根據id查詢商品信息安全方式")

? ? selectID = input('請輸入要執行的功能編號:')

? ? if selectID == '1':

? ? ? ? # 查詢所有商品信息

? ? ? ? self.fetch_all_info()

? ? elif selectID == '2':

? ? ? ? # 查詢種類信息

? ? ? ? self.fetch_cate()

? ? elif selectID == '3':

? ? ? ? # 查詢品牌信息

? ? ? ? self.fetch_brand()

? ? elif selectID == '4':

? ? ? ? # 添加一個商品類型

? ? ? ? self.add_info()

? ? elif selectID == '5':

? ? ? ? # 通過ID 查找商品

? ? ? ? self.find_info()

? ? elif selectID == '6':

? ? ? ? # 通過ID 查找商品 防SQL注入

? ? ? ? self.find_info_safe()

? ? else:

? ? ? ? print('輸入行號不正確!')

? 5>實現一個顯示方法,用來輸出結果

# 用來顯示結果的方法,私有,對外不可見

def __show_result(self, result):

for t in result:

? ? print(t)

? 6>實現查詢所有商品方法

# 查詢所有商品信息

def fetch_all_info(self):

sql_str = ''' select * from goods;'''

self.__cur.execute(sql_str)

self.__show_result(self.__cur.fetchall())

? 7>查詢種類信息

# 查詢種類信息

def fetch_cate(self):

sql_str = ''' select * from goods_cates;'''

self.__cur.execute(sql_str)

self.__show_result(self.__cur.fetchall())

? 8>查詢品牌信息

# 查詢品牌信息

def fetch_brand(self):

sql_str = ''' select * from goods_brands;'''

self.__cur.execute(sql_str)

self.__show_result(self.__cur.fetchall())

? 9>添加商品類型

# 添加商品類型

def add_info(self):

new_type = input('請輸入商品類型:')

sql_str = ''' insert into goods_cates values(0,"%s");'''% new_type #注意,這里占位符要加引號

self.__cur.execute(sql_str)

self.__conn.commit() # 修改操作要手動提交

? 10>根據id 查找商品

# 根據id查找商品

def find_info(self):

id = input('請輸入ID:')

sql_str = ''' select * from goods where id=%s;'''%id

self.__cur.execute(sql_str)

self.__show_result(self.__cur.fetchall())

? 11>根據id 查找商品,案例防注入

# 根據id查找商品,案例防SQL注入

def find_info_safe(self):

id = input('請輸入ID:')

sql_str = ''' select * from goods where id=%s;'''

self.__cur.execute(sql_str,(id,))

self.__show_result(self.__cur.fetchall())


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

推薦閱讀更多精彩內容