pymysql操作mysql詳解

前言

在之前幾天的日記中,各位可以看到我在保存數據時用的基本上都是 MySQL 數據庫,而我用的也是 pymysql 來操作 MySQL,pymysql 則是一個純 Python 實現的 MySQL 客戶端操作庫

今天呢就來講講 pymysql 的使用,事實上我覺得看起來用 pymysql 來操作 MySQL 的代碼會顯得比較繁雜,之後也會講講 Python 操作 MongoDBRedis 等數據庫的庫

這裏便不再贅述 MySQL 有關的詳細的知識點,有需要的話可以看看這裏
MySQL 教程
《深入淺出mysql》學習筆記

正文

安裝...就不用多說了8

python3 -m pip install PyMySQL

我們來看看官方給出的栗子

# 表結構
CREATE TABLE `users` (
    `id` int(11) NOT NULL AUTO_INCREMENT,  # id 整型 不能爲空 自動增長
    `email` varchar(255) COLLATE utf8_bin NOT NULL,  # 郵箱 可變字符串 區分大小寫,不能爲空
    `password` varchar(255) COLLATE utf8_bin NOT NULL,  # 密碼 可變字符串 區分大小寫,不能爲空
    PRIMARY KEY (`id`)  # id 爲主鍵
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin
AUTO_INCREMENT=1 ;
# InnoDB 引擎 默認 utf-8 編碼 區分大小寫 自動增長從1開始
import pymysql.cursors

# 連接數據庫
connection = pymysql.connect(host='localhost',
                             user='user',
                             password='passwd',
                             db='db',
                             charset='utf8mb4',
                             cursorclass=pymysql.cursors.DictCursor)

try:
    with connection.cursor() as cursor:
        # 創建一條新的記錄
        sql = "INSERT INTO `users` (`email`, `password`) VALUES (%s, %s)"
        cursor.execute(sql, ('[email protected]', 'very-secret'))

    # 連接完數據庫並不會自動提交,所以需要手動 commit 你的改動
    connection.commit()

    with connection.cursor() as cursor:
        # 讀取單條記錄
        sql = "SELECT `id`, `password` FROM `users` WHERE `email`=%s"
        cursor.execute(sql, ('[email protected]',))
        result = cursor.fetchone()
        print(result)
finally:
    connection.close()

這裏注意連續用了兩處 with 好處就在於 with 結束後會自動 close cursor 而免去了 cursor.close()

輸出

{'password': 'very-secret', 'id': 1}

數據庫連接

connection = pymysql.connect(host='localhost',
                             user='user',
                             password='passwd',
                             db='db',
                             charset='utf8mb4',
                             cursorclass=pymysql.cursors.DictCursor)

這裏除了 host、user、password 等還有很多參數可以選擇 詳見

參數 解釋
host 數據庫服務器地址,默認 localhost
user 用戶名,默認爲當前程序運行用戶
password 登錄密碼,默認爲空字符串
database 默認操作的數據庫
port 數據庫端口,默認爲 3306
bind_address 當客戶端有多個網絡接口時,指定連接到主機的接口。參數可以是主機名或IP地址。
unix_socket unix 套接字地址,區別於 host 連接
read_timeout 讀取數據超時時間,單位秒,默認無限制
write_timeout 寫入數據超時時間,單位秒,默認無限制
charset 數據庫編碼
sql_mode 指定默認的 SQL_MODE
read_default_file Specifies my.cnf file to read these parameters from under the [client] section.
conv Conversion dictionary to use instead of the default one. This is used to provide custom marshalling and unmarshaling of types.
use_unicode Whether or not to default to unicode strings. This option defaults to true for Py3k.
client_flag Custom flags to send to MySQL. Find potential values in constants.CLIENT.
cursorclass 設置默認的遊標類型
init_command 當連接建立完成之後執行的初始化 SQL 語句
connect_timeout 連接超時時間,默認 10,最小 1,最大 31536000
ssl A dict of arguments similar to mysql_ssl_set()’s parameters. For now the capath and cipher arguments are not supported.
read_default_group Group to read from in the configuration file.
compress Not supported
named_pipe Not supported
autocommit 是否自動提交,默認不自動提交,參數值爲 None 表示以服務器爲準
local_infile Boolean to enable the use of LOAD DATA LOCAL command. (default: False)
max_allowed_packet 發送給服務器的最大數據量,默認爲 16MB
defer_connect 是否惰性連接,默認爲立即連接
auth_plugin_map A dict of plugin names to a class that processes that plugin. The class will take the Connection object as the argument to the constructor. The class needs an authenticate method taking an authentication packet as an argument. For the dialog plugin, a prompt(echo, prompt) method can be used (if no authenticate method) for returning a string from the user. (experimental)
server_public_key SHA256 authenticaiton plugin public key value. (default: None)
db 參數 database 的別名
passwd 參數 password 的別名
binary_prefix Add _binary prefix on bytes and bytearray. (default: False)

遊標

連接完數據庫,接着就該獲取遊標,之後才能進行執行、提交等操作
cursor = connection.cursor()

查詢時,默認返回的數據類型爲元組,可以修改返回類型
幾種常用遊標類型:

  • Cursor: 默認,元組類型
  • DictCursor: 字典類型
  • SSCursor: 無緩衝元組類型
  • SSDictCursor: 無緩衝字典類型

無緩衝遊標類型,適用於數據量很大,一次性返回太慢,或者服務端帶寬較小

創建連接時,通過cursorclass 參數指定類型:

connection = pymysql.connect(host='localhost',
                             user='root',
                             password='root',
                             db='db',
                             charset='utf8',
                             cursorclass=pymysql.cursors.DictCursor)

也可以在創建遊標時指定類型:

cursor = connection.cursor(cursor=pymysql.cursors.DictCursor)

遊標移動

所有的數據查詢操作均基於遊標,我們可以通過cursor.scroll(num, mode)控制遊標的位置。

cursor.scroll(1, mode='relative') # 相對當前位置移動
cursor.scroll(2, mode='absolute') # 相對絕對位置移動

sql語句

我的習慣是先寫好要操作的語句,如插入、更新、刪除等,同時也要注意 pymysql 中所有的有關更新數據(insertupdatedelete)的操作都需要 commit,否則無法將數據提交到數據庫

# 插入語句
insert_sql = "insert into `jd_huawei` (`pid`, `url`, `price`, " \
                     "`refprice`, `name`, `comment_num`, `comment_type`)values('%s','%s','%s'," \
                     "'%s','%s','%s','%s')" % (info_id, info_url, price, refprice, name, comment_num, comment_types)
# 查詢語句
select_sql = "select `pid` from `jd_huawei` where `pid`='%s'" % info_id

最後一條ID

cursor提供一個參數可以獲取最新 insert 自增的 id ,也就是最後插入的一條數據ID,如果沒有insert過,執行cursor.lastrowid會報錯

執行sql語句

cursor.execute(sql, args)
這裏的參數 args 可以是,tuple,list,dict,另外 execute 還能返回受影響的行數

influence_num = cursor.execute(sql, args)
print(type(influence_num))  # int

cursor.executemany(sql, args)
可以批量執行

查詢獲取數據

查詢表中的全部數據
select * from table

取出全部的數據,可以返回一個結果集
fetchall()

取出一定數量的數據
fetchmany(size)

取出一條數據
fetchone()

事務處理

事務開始(這個我好像沒怎麼用)
connection.begin()

提交修改
connection.commit()

事務回滾
connection.rollback()

兩個close

一般用於最後結束對數據庫的操作,可在 finally 中寫

關閉數據庫連接
connection.close()

關閉遊標
cursor.close()

還有防止 sql 注入

通過操作輸入來修改後臺SQL語句

#正常構造語句的情況
sql="select user,pass from tb7 where user='%s' and pass='%s'" % (user,passwd)
row_count=cursor.execute(sql)
#拼接語句被構造成下面這樣,永真條件,此時就注入成功了。
select user,pass from tb7 where user='u1' or '1'-- ' and pass='u1pass'

要避免這種情況可以使用 pymysql 提供的參數化查詢

#避免注入,使用pymysql提供的參數化語句
user="u1' or '1'-- "
passwd="u1pass"
#執行參數化查詢
row_count=cursor.execute("select user,pass from tb7 where user=%s and pass=%s",(user,passwd))

# 內部執行參數化生成的SQL語句,對特殊字符進行了加\轉義,避免注入語句生成。
sql=cursor.mogrify("select user,pass from tb7 where user=%s and pass=%s",(user,passwd))
print(sql)
# 被轉義的語句
select user,pass from tb7 where user='u1\' or \'1\'-- ' and pass='u1pass'

最後

最後再來看看之前寫的插入數據庫的代碼,是不是更加清晰了

    def insertmysql(info_id, info_url, price, refprice, name, comment_num, comment_types):
        conn_insert = pymysql.connect(host='localhost', port=3306, user='', password='', db='jingdong')
        cursor_ins = conn_insert.cursor()

        insert_sql = "insert into `jd_huawei` (`pid`, `url`, `price`, " \
                     "`refprice`, `name`, `comment_num`, `comment_type`)values('%s','%s','%s'," \
                     "'%s','%s','%s','%s')" % (info_id, info_url, price, refprice, name, comment_num, comment_types)
        try:
            select_sql = "select `pid` from `jd_huawei` where `pid`='%s'" % info_id
            response = cursor_ins.execute(select_sql)
            conn_insert.commit()
            if response == 1:
                print(u'該手機已存在...')
            else:
                try:
                    cursor_ins.execute(insert_sql)
                    conn_insert.commit()
                    print(u'更新成功...')
                except Exception as e:
                    print(u'更新錯誤...', e)
                    conn_insert.rollback()
        except Exception as e:
            print(u'查詢錯誤...', e)
            conn_insert.rollback()
        finally:
            cursor_ins.close()
            conn_insert.close()

print('微信公衆號搜索 "猿獅的單身日常" ,Java技術升級、蟲師修煉,我們 不見不散!')
print('也可以掃下方二維碼哦~')
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章