Python 如何優(yōu)雅的操作 PyMySQL

一、PyMysql

在使用Python操作MySQL數(shù)據(jù)過的過程中悍及,基本的增刪改查操作如何更加高效優(yōu)雅的執(zhí)行镣煮。這里將以PyMySQL為例义钉,介紹一下如何使用Python操作數(shù)據(jù)庫。 Python對MySQL數(shù)據(jù)庫進行操作氓英,基本思路是先連接數(shù)據(jù)庫 Connection 對象侯勉,建立游標(biāo) Cursor 對象,然后執(zhí)行SQL語句對數(shù)據(jù)庫進行操作铝阐,獲取執(zhí)行結(jié)果址貌,最終斷開連接。大致過程是這樣徘键,在對其進行介紹之前练对,先介紹一些基本的概念。

Connection

Connection 對象即為數(shù)據(jù)庫連接對象吹害,在python中可以使用pymysql.connect()方法創(chuàng)建Connection對象螟凭,該方法的常用參數(shù)如下:

host:IP地址,字符串類型
user:用戶名, 字符串類型
passwd:無默認值;字符串類
db:數(shù)據(jù)庫名稱赠制,無默認值赂摆;字符串類型(可以不傳但是SQL中必須體現(xiàn))
port:端口, 默認為3306, 整型
charset:設(shè)置utf8, 字符串類型
close:關(guān)閉當(dāng)前連接對象

Cursor

Cursor對象即為游標(biāo)對象,用于執(zhí)行查詢和獲取結(jié)果钟些,在python中可以使用connect.cursor()創(chuàng)建

execute():執(zhí)行數(shù)據(jù)庫單個查詢或命令烟号,將結(jié)果從數(shù)據(jù)庫獲取
executemany(): 對一個查詢運行多個數(shù)據(jù),其返回是:受影響的行數(shù)(如果有的話)
close():關(guān)閉當(dāng)前游標(biāo)對象

Transaction

1.事務(wù)是數(shù)據(jù)庫理論中一個比較重要的概念政恍,指訪問和更新數(shù)據(jù)庫的一個程序執(zhí)行單元汪拥,具有ACID特性:

原子性(Atomic):事務(wù)中的各項操作要么全都做,要么全都不做篙耗,任何一項操作的失敗都會導(dǎo)致整個事務(wù)的失敗
一致性(Consistent):事務(wù)必須使數(shù)據(jù)庫從一個一致性狀態(tài)變到另一個一致性狀態(tài)
隔離性(Isolated):并發(fā)執(zhí)行的事務(wù)彼此無法看到對方的中間狀態(tài)迫筑,一個事務(wù)的執(zhí)行不能被其他事務(wù)干擾
持久性(Durable):事務(wù)一旦提交宪赶,它對數(shù)據(jù)庫的改變就是永久性的,可以通過日志和同步備份在故障發(fā)生后重建數(shù)據(jù)脯燃。

2.常用事務(wù)方法

Connection.commit():正常事務(wù)提交
Connection.rollback():事務(wù)異陈蓿回滾
Connection.autocommit():事務(wù)自動提交機制,默認TRUE辕棚,設(shè)置FALSE則關(guān)閉欲主。

二、Python操作MySQL

1.安裝

$ pip3 install PyMySQL

2.數(shù)據(jù)庫連接
        import pymysql
 
        # 打開數(shù)據(jù)庫連接
        db = pymysql.connect(host='127.0.0.1',
                             user='user',
                             password='123456',
                             database='demo',
                             port=3306,
                             charset='utf8')
         
        # 使用 cursor() 方法創(chuàng)建一個游標(biāo)對象 cursor
        cursor = db.cursor()
         
        # 使用 execute()  方法執(zhí)行 SQL 查詢 
        cursor.execute("SELECT * FROM USER;")
         
        # 使用 fetchone() 方法獲取單條數(shù)據(jù).
        data = cursor.fetchone()
         
        print ("Database data : %s " % data)
         
        # 關(guān)閉數(shù)據(jù)庫連接
        cursor.close()
        db.close()
    
3.數(shù)據(jù)庫DML操作
事務(wù)執(zhí)行過程
        import pymysql
 
        # 打開數(shù)據(jù)庫連接
        db = pymysql.connect(**config) # 省略連接信息
         
        # 使用cursor()方法獲取操作游標(biāo) 
        cursor = db.cursor()
         
        # SQL插入語句
        sql = """INSERT INTO EMPLOYEE(FIRST_NAME,
                 LAST_NAME, AGE, SEX, INCOME)
                 VALUES ('Mac', 'Mohan', 20, 'M', 2000)"""
        try:
           # 執(zhí)行sql語句
           cursor.execute(sql)
           
           # 提交到數(shù)據(jù)庫執(zhí)行
           db.commit()
        except:
           # 如果發(fā)生錯誤則回滾
           db.rollback()
         
        # 關(guān)閉當(dāng)前游標(biāo)對象
        cursor.close()
        # 關(guān)閉數(shù)據(jù)庫連接
        db.close()
        
        # 執(zhí)行傳入的SQL也可以更加的靈活逝嚎,可以使用另外一種%s 占位符扁瓢,后續(xù)的參數(shù)依次傳入。
        sql2 = """INSERT INTO EMPLOYEE(FIRST_NAME,
                 LAST_NAME, AGE, SEX, INCOME)
                 VALUES ('%s', '%s', %s, '%s', %s)"""
        cursor.execute(sql2, 'Mac', 'Mohan', 20, 'M', 2000)
4.數(shù)據(jù)庫DQL操作

Python查詢Mysql使用常用幾個方法补君。

fetchone(): 該方法獲取下一個查詢結(jié)果集引几。結(jié)果集是一個對象.
fetchmany():獲取結(jié)果集的指定幾行.
fetchall(): 接收全部的返回結(jié)果行.
rowcount: 這是一個只讀屬性,并返回執(zhí)行execute()方法后影響的行數(shù)挽铁。

        import pymysql
         
        # 打開數(shù)據(jù)庫連接
        db = pymysql.connect(**config)
         
        # 使用cursor()方法獲取操作游標(biāo) 
        cursor = db.cursor()
         
        # SQL 查詢語句
        sql = "SELECT * FROM EMPLOYEE WHERE INCOME > %s" % (1000)
        try:
           # 執(zhí)行SQL語句
           cursor.execute(sql)
           # 獲取所有記錄列表
           result1=cursor.fetchone()
           result2=cursor.fetchmany(2)
           results = cursor.fetchall()
           print(result1)
           print(result2)
           print(results)
        except:
           print ("Error: unable to fetch data")
         
        # 關(guān)閉數(shù)據(jù)庫連接
        cursor.close()
        db.close()

三伟桅、工具類封裝

通過封裝常用方法將會大大降低對數(shù)據(jù)庫操作的成本。接下來分為幾步進行操作:
1.可以通過env文件來存儲數(shù)據(jù)庫的連接信息
2.將env文件數(shù)據(jù)加載進系統(tǒng)環(huán)境變量
3.從系統(tǒng)環(huán)境變量中獲取對應(yīng)連接數(shù)據(jù)
4.連接數(shù)據(jù)庫屿储,操作增刪改查

# .env
DB_INFO={"host": "127.0.0.1","port":3306,"user": "user","passwd": "123456","charset": "utf8"}
import io
import os


class EnvironmentVarUtils(object):
    def __init__(self, fileName=None):
        self.file_name = fileName
        self._load_dot_env_file(self._get_environment_path())

    def _get_environment_path(self):
        """
        :return: project_path
        """
        return os.path.join(os.path.dirname(os.getcwd()), '.env') if self.file_name is None\
            else os.path.join(os.path.dirname(os.getcwd()), self.file_name)

    def _load_dot_env_file(self, dot_env_path):
        """ load .env file.
        Args:
            dot_env_path (str): .env file path
        """
        if not os.path.isfile(dot_env_path):
            raise FileNotFoundError(".env file not found Error.")

        print("Loading environment variables from 【{}】".format(dot_env_path))
        env_variables_mapping = {}

        with io.open(dot_env_path, 'r', encoding='utf-8') as fp:
            for line in fp:
                if "=" in line:
                    variable, value = line.split("=", 1)
                else:
                    raise Exception(".env format error")

                env_variables_mapping[variable.strip()] = value.strip()
        self._set_os_environ(env_variables_mapping)

    @staticmethod
    def _set_os_environ(variables_mapping):
        """ set variables mapping to os.environ """
        for variable in variables_mapping:
            os.environ[variable] = variables_mapping[variable]
            print("Set OS environment variable: {}".format(variable))

    @staticmethod
    def get_os_environ(variable_name):
        """ get value of environment variable.
        """
        try:
            return os.environ[variable_name]
        except Exception as e:
            raise e
import pymysql


class SqlHelper(object):
    def __init__(self, config):
        self.connect = pymysql.connect(**eval(config))
        self.connect.autocommit(True)
        # default return tuple, DictCursor return Json .
        self.cursor = self.connect.cursor()

    def __enter__(self):
        # DictCursor return Json .
        self.cursor = self.connect.cursor(cursor=pymysql.cursors.DictCursor)
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.cursor.close()
        self.connect.close()

    def queryAll(self, sql, params=None):
        """
        :param sql:
        :param params:
        :return:
        """
        self.cursor.execute(sql, params)
        return self.cursor.fetchall()

    def queryMany(self, sql, num, params=None):
        """
        :param sql:
        :param num:
        :param params:
        :return:
        """
        self.cursor.execute(sql, params)
        return self.cursor.fetchmany(num)

    def queryOne(self, sql, params=None):
        """
        :param sql:
        :param params:
        :return:
        """
        self.cursor.execute(sql, params)
        return self.cursor.fetchone()

    def operation(self, sql, params=None, DML=True):
        """
        DML: insert / update / delete
        DDL: CREATE TABLE/VIEW/INDEX/SYN/CLUSTER
        :param DML:
        :param sql:
        :param params:
        :return:
        """
        try:
            self.cursor.execute(sql, params)
        except Exception as e:
            if DML:
                self.connect.rollback()
            raise e

    def batch_operation(self, sql_list, params_list=None, DML=True):
        """
            Process multiple SQL files in batches .
        :param DML:
        :param sql_list:
        :param params_list:
        :return:
        """
        for i in range(len(sql_list)):
            try:
                if params_list is not None:
                    self.operation(sql_list[i], params_list[i], DML)
                else:
                    self.operation(sql_list[i], params_list, DML)
            except Exception as e:
                raise e


    def batch_processing(self, sql, params_list, DML=True):
        """
         The same SQL is executed multiple times in batches.
        :param DML:
        :param sql:
        :param params_list:
        :return:
        """
        try:
            self.cursor.executemany(sql, params_list)
        except Exception as e:
            if DML:
                self.connect.rollback()
            raise e

    def __del__(self):
        """
            Automatic disconnection
        :return:
        """
        if self.connect.open:  # 解決連接重復(fù)關(guān)閉的
            self.cursor.close()
            self.connect.close()

1.正常方式執(zhí)行

if __name__ == '__main__':
    sql = "select age from `demo`.`user` where name= 'Amy';"
    env = EnvironmentVarUtils()  # 初始化對象加載env文件數(shù)據(jù)
    config = env.get_os_environ("DB_INFO")  # 獲取指定key數(shù)據(jù)

    # 1.正常方式執(zhí)行
    db = SqlHelper(config)
    result = db.queryOne(sql)
    print(result)

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

控制臺輸出:

Loading environment variables from 【C:\Users\lenovo\PycharmProjects\job\httpRunner_demo\.env】
Set OS environment variable: USERNAME
Set OS environment variable: PASSWORD
Set OS environment variable: BASE_URL
Set OS environment variable: db_info
(18,)

Process finished with exit code 0

2.通過上下文管理的方式執(zhí)行

if __name__ == '__main__':
    sql = "select age from `demo`.`user` where name= 'Amy';"
    env = EnvironmentVarUtils()  # 初始化對象加載env文件數(shù)據(jù)
    config = env.get_os_environ("DB_INFO")  # 獲取指定key數(shù)據(jù)

    # 2.上下文管理方式執(zhí)行
    with SqlHelper(config) as db:
        result = db.queryOne(sql)
        print(result)

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

控制臺輸出:

Loading environment variables from 【C:\Users\lenovo\PycharmProjects\job\httpRunner_demo\.env】
Set OS environment variable: USERNAME
Set OS environment variable: PASSWORD
Set OS environment variable: BASE_URL
Set OS environment variable: db_info
{'age': 18}

Process finished with exit code 0

以上親測可用贿讹,可以嘗試在自動化項目實踐中操作。有問題歡迎留言討論够掠。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末民褂,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子疯潭,更是在濱河造成了極大的恐慌赊堪,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件竖哩,死亡現(xiàn)場離奇詭異哭廉,居然都是意外死亡,警方通過查閱死者的電腦和手機相叁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門遵绰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人增淹,你說我怎么就攤上這事椿访。” “怎么了虑润?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵成玫,是天一觀的道長。 經(jīng)常有香客問我,道長哭当,這世上最難降的妖魔是什么猪腕? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮钦勘,結(jié)果婚禮上陋葡,老公的妹妹穿的比我還像新娘。我一直安慰自己彻采,他們只是感情好脖岛,可當(dāng)我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著颊亮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪陨溅。 梳的紋絲不亂的頭發(fā)上终惑,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天,我揣著相機與錄音门扇,去河邊找鬼雹有。 笑死,一個胖子當(dāng)著我的面吹牛臼寄,可吹牛的內(nèi)容都是我干的霸奕。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼吉拳,長吁一口氣:“原來是場噩夢啊……” “哼质帅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起留攒,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤煤惩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后炼邀,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體魄揉,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年拭宁,在試婚紗的時候發(fā)現(xiàn)自己被綠了洛退。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡杰标,死狀恐怖兵怯,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情在旱,我是刑警寧澤摇零,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響驻仅,放射性物質(zhì)發(fā)生泄漏谅畅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一噪服、第九天 我趴在偏房一處隱蔽的房頂上張望毡泻。 院中可真熱鬧,春花似錦粘优、人聲如沸仇味。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽丹墨。三九已至,卻和暖如春嬉愧,著一層夾襖步出監(jiān)牢的瞬間贩挣,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工没酣, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留王财,地道東北人。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓裕便,卻偏偏與公主長得像绒净,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子偿衰,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(nèi)容