Python Every Day, 第 20 天 在工作中,不管Web開(kāi)發(fā)或者爬蟲(chóng),數(shù)據(jù)分析等凡是與數(shù)據(jù)有接觸的都離不開(kāi)數(shù)據(jù)庫(kù)。數(shù)據(jù)庫(kù)又分為關(guān)系型數(shù)據(jù)庫(kù)還是非關(guān)系型數(shù)據(jù)庫(kù),關(guān)系型數(shù)據(jù)庫(kù)中最常用應(yīng)該就是MySQL了。在Python中可以通過(guò)PyMySQL庫(kù)完成對(duì)其的操作。安裝PyMySQL 操作過(guò)程大概分為如下幾步 0、在MySQL中創(chuàng)建庫(kù)和表1、創(chuàng)建數(shù)據(jù)庫(kù)連接2、創(chuàng)建cursor,用于執(zhí)行sql通過(guò)下面一個(gè)簡(jiǎn)單的例子給大家演示一下 創(chuàng)建test庫(kù),并在該庫(kù)中創(chuàng)建fund_info(資產(chǎn)信息表)CREATE DATABASE `test` ; use test; CREATE TABLE `fund_info` ( `id` int(11) NOT NULL AUTO_INCREMENT, `account` varchar(50) NOT NULL COMMENT '賬號(hào)', `amount` decimal(10,2) DEFAULT NULL COMMENT '總金額', `consume` decimal(10,2) DEFAULT '0.00' COMMENT '消費(fèi)金額', `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP, `modify_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1
具體操作(增刪改查)看示例代碼吧,在代碼中盡可能的都注釋了。import pymysql
# 創(chuàng)建MySQL連接 connection = pymysql.connect(host='127.0.0.1', # MySQL服務(wù)器地址 port=3306, # 服務(wù)端口號(hào) user='root', # MySQL用戶名 password='root', # MySQL密碼 db='test', # 要操作的數(shù)據(jù)庫(kù)名稱(chēng) charset='utf8mb4') # 連接編碼 # 創(chuàng)建cursor, 用于執(zhí)行sql cursor = connection.cursor()
# 增加兩條記錄。 insert_sql = 'insert into fund_info (account, amount) values ('abc@163.com', 100.00)' insert_sql1 = 'insert into fund_info (account, amount) values ('zxc@163.com', 99.00)' # 執(zhí)行上面兩個(gè)sql, cursor.execute(insert_sql) cursor.execute(insert_sql1) # 執(zhí)行增 刪 改時(shí) 需要commit,不然不會(huì)生效 connection.commit()
# 查詢(xún)剛才插入的兩條數(shù)據(jù) cursor.execute('select * from fund_info') # fetchall 查看執(zhí)行的全部結(jié)果,返回一個(gè)tuple result_all = cursor.fetchall() ''' 輸出: result_all : ((2, 'abc@163.com', Decimal('100.00'), Decimal('0.00'), datetime.datetime(2019, 8, 7, 16, 57, 49), datetime.datetime(2019, 8, 7, 16, 57, 49)), (3, 'zxc@163.com', Decimal('99.00'), Decimal('0.00'), datetime.datetime(2019, 8, 7, 16, 57, 49), datetime.datetime(2019, 8, 7, 16, 57, 49))) ''' print('result_all :', result_all)
# 通過(guò)id查詢(xún) cursor.execute('select amount from fund_info where account='abc@163.com'') # fetone 仍然返回元組 result_amount = cursor.fetchone() print(result_amount) # (Decimal('100.00'),)
# 更新 賬號(hào):abc@163.com 的amount值為200.00 cursor.execute('update fund_info set amount=200.00 where account='abc@163.com'') # 執(zhí)行增 刪 改時(shí) 需要commit,不然不會(huì)生效 connection.commit() print('更新成功.')
cursor.execute('delete from fund_info where account='abc@163.com'') # 執(zhí)行增 刪 改時(shí) 需要commit,不然不會(huì)生效 connection.commit() print('刪除成功.')
# 操作完畢之后,必須要關(guān)閉連接 cursor.close() connection.close()
以上是用PyMySQL操作MySQL的基本知識(shí)。這里想再啰嗦一下事務(wù)。事務(wù)
事務(wù): 事務(wù)指邏輯上的一組操作,組成這組操作的各個(gè)單元,要不全部成功,要不全部不成功。通俗的將:我執(zhí)行多個(gè)sql如果其中一個(gè)失敗了,那要將之前修改的數(shù)據(jù)進(jìn)行還原。回滾到執(zhí)行前的狀態(tài)。拿我們上面的sql來(lái)舉例,對(duì)于一個(gè)賬號(hào) account,資金amount、消費(fèi)金額consume。我們購(gòu)物的時(shí)候,消費(fèi)金額增加的同時(shí),錢(qián)包里的金額就要對(duì)應(yīng)的減少。 這個(gè)增加和減少就是一個(gè)事務(wù),不可能只增加消費(fèi)金額,而不減少總金額。今天只說(shuō)一下PyMySQL對(duì)事務(wù)的處理(如果在MySQL終端進(jìn)行事務(wù)操作,需要手動(dòng)開(kāi)啟 -- start transaction;)mysql> select amount from fund_info where account = 'zxc@163.com'; +--------+ | amount | +--------+ | 99.00 | +--------+ 1 row in set (0.00 sec)
import pymysql
connection = pymysql.connect(host='127.0.0.1', # MySQL服務(wù)器地址 port=3306, # 服務(wù)端口號(hào) user='root', # MySQL用戶名 password='root', # MySQL密碼 db='test', # 要操作的數(shù)據(jù)庫(kù)名稱(chēng) charset='utf8mb4') # 連接編碼 # 創(chuàng)建cursor, 用于執(zhí)行sql cursor = connection.cursor()
# 代表消費(fèi)的金額 price = 15
# 此時(shí)賬戶zxc的總金額為99 # 賬戶zxc@163.com 總金額 - price sql_1 = f'update fund_info set amount = amount - {price} where account = 'zxc@163.com'' # 賬戶zxc@163.com 消費(fèi)金額 + price sql_2 = f'update fund_info set consume = consume + {price} where account = 'zxc@163.com''
try: # 查詢(xún)余額是否足夠 cursor.execute('select amount from fund_info where account = 'zxc@163.com'') result = cursor.fetchone() print(result[0]) # 如果余額不足 拋出異常. if not result or result[0] < price: raise Exception('余額不足...') cursor.execute(sql_1) print('========= 其他業(yè)務(wù)邏輯 執(zhí)行中....') cursor.execute(sql_2) except Exception as e: # 事務(wù)回滾 connection.rollback() print(e) finally: # 提交sql connection.commit() # 關(guān)閉連接 cursor.close() connection.close()
mysql> select amount from fund_info where account = 'zxc@163.com'; +--------+ | amount | +--------+ | 84.00 | +--------+ 1 row in set (0.00 sec)
在代碼中通過(guò)raise 模擬異常。演示一下事務(wù)的作用import pymysql
connection = pymysql.connect(host='127.0.0.1', # MySQL服務(wù)器地址 port=3306, # 服務(wù)端口號(hào) user='root', # MySQL用戶名 password='root', # MySQL密碼 db='test', # 要操作的數(shù)據(jù)庫(kù)名稱(chēng) charset='utf8mb4') # 連接編碼 # 創(chuàng)建cursor, 用于執(zhí)行sql cursor = connection.cursor()
# 代表消費(fèi)的金額 price = 15
# 此時(shí)賬戶zxc的總金額為99 # 賬戶zxc@163.com 總金額 - price sql_1 = f'update fund_info set amount = amount - {price} where account = 'zxc@163.com'' # 賬戶zxc@163.com 消費(fèi)金額 + price sql_2 = f'update fund_info set consume = consume + {price} where account = 'zxc@163.com''
try: # 查詢(xún)余額是否足夠 cursor.execute('select amount from fund_info where account = 'zxc@163.com'') result = cursor.fetchone() print(result[0]) # 如果余額不足 拋出異常. if not result or result[0] < price: raise Exception('余額不足...') cursor.execute(sql_1) print('========= 其他業(yè)務(wù)邏輯 執(zhí)行中....') raise Exception('模擬業(yè)務(wù)邏輯異常......') cursor.execute(sql_2) except Exception as e: print('---- 開(kāi)始事務(wù)回滾') # 事務(wù)回滾 connection.rollback() print(e) finally: # 提交sql connection.commit() # 關(guān)閉連接 cursor.close() connection.close() print('執(zhí)行完畢')
控制條輸出 ========= 其他業(yè)務(wù)邏輯 執(zhí)行中.... ---- 開(kāi)始事務(wù)回滾 模擬業(yè)務(wù)邏輯異常...... 執(zhí)行完畢
查詢(xún)mysql mysql> select amount from fund_info where account = 'zxc@163.com'; +--------+ | amount | +--------+ | 84.00 | +--------+ 1 row in set (0.00 sec)
即使執(zhí)行了sql_1(減少總金額的sql語(yǔ)句),金額并沒(méi)有被改變。因?yàn)樵谛薷腸onsume(執(zhí)行sql_2)之前程序出現(xiàn)了異常,程序就進(jìn)行了事務(wù)回滾,即:connection.rollback()。所以數(shù)據(jù)被還原到了執(zhí)行事務(wù)之前的樣子。 以上,便是今天的分享,希望大家喜歡,覺(jué)得內(nèi)容不錯(cuò)的,歡迎點(diǎn)擊「在看」支持,謝謝各位。
|