話不多說,本博的一個技術 python對mysql的操作的三種實現方式。
再此之前先引入三個知識點:
1 :__name__=='__main__'
這是什么意思呢?
1.python文件的后綴為.py
2..py文件既可以用來直接執行,也可以用來作為模塊被導入,
3.在python中用import導入模塊
__name__作為模塊的內置屬性,簡單點說,就是.py文件的調用方式,如果是以模塊調用__name__就等於該模塊的名字(后文會繼續說明),如果是直接調用__name__就等於'__main__'
2:命令行傳參
何為命令行傳參? 顧名思義 ,是在命令行傳遞參數,和常見的傳遞參數方式不同的是,命令行傳遞參數是把參數和程序寫在同一個命令行來運行。
給個實際的圖片看一下(我用的是linux環境,如果在windows下可用dos實現):
這里python3 是執行python程序的格式,pyt3.py 和pyt2.py是 .py程序的名字,而后面的 100 101 3都是參數。
明確了這個之后,引入一個庫,sys庫,這個庫可以支持對命令行傳遞過來的參數的一些操作(后文會繼續說明)。
3:pymysql這個庫
注意,在python3以上版本已經不支持mysqldb這個庫了,不過兩者的方法基本相同。
這個庫的用法主要步驟如下:
1:建立connection
2:獲取cursor(可以把它當做一個游標)
3:執行sql語句
4:事務出現異常?
n:con.commit
y:con.rollback
5:獲取執行sql后的數據
cursor.fetch
這里提到了事務,事務又是什么呢。簡單的說,一個事務包含的所有操作都是原子操作 即 要么都執行 要么都不執行,事務有什么用呢(后文會繼續說明)
好了,回歸正題,那么python操作mysql數據庫有哪三種方式呢? 以銀行轉賬為例,先看第一種
1:普通方式
import pymysql import sys con=pymysql.Connect(host='xxx.xxx.xx.xx',port=3306,db='pytest',user='root', passwd='xxx',charset='utf8') cursor=con.cursor() def is_ava(acctid): sel_sql='select * from account where acctid=%s'%acctid cursor.execute(sel_sql) rs=cursor.fetchone() try: len(rs) except: return False return True def mon_ava(acctid,mon): selm_sql='select *from account where acctid=%s and money>=%s'%(acctid,mon) cursor.execute(selm_sql) rs=cursor.fetchone() try: len(rs) except: return False return True sr_id=sys.argv[1] tr_id=sys.argv[2] dt_money=sys.argv[3] if is_ava(sr_id) and is_ava(tr_id): if mon_ava(sr_id,dt_money): rm_sql=' update account set money=money-%s where acctid=%s'%(dt_money,sr_id) add_sql=' update account set money=money+%s where acctid=%s'%(dt_money,tr_id) try: cursor.execute(rm_sql) cursor.execute(add_sql) con.commit() except: con.rollback() finally: cursor.close() con.close()
這里純粹是面向過程的編程思想,注意代碼最后的try ,except 這里就是一個完整的事務流程,當執行remove 和add出現了異常 就進行rollback()rollback的作用就是回滾到sql語句執行前的狀態。
為什么要這樣呢? 試想這種情況:A給B的銀行卡轉賬100塊錢,即A-100 B+100.而B在此之前把此銀行卡注銷掉了, 如果不進行事務操作 就會出現:A白白丟失100塊錢的情況
而我們期望的情況是這樣:A-100 B+100 ,如果轉賬過程中出現了異常,A、B的金額都保持不變。使用事務這種原子性操作就可以確保操作的安全。
2:下面看第二種方法 面向對象方式:
# -*- coding: utf-8 -*- import pymysql import sys class TransforMoney(object): def __init__(self,con): self.con=con self.cursor=self.con.cursor() def is_ava(self,acctid): sel_sql='select * from account where acctid=%s'%acctid self.cursor.execute(sel_sql) rs=self.cursor.fetchone() try: len(rs) except: raise Exception def mon_ava(self,acctid,mon): selm_sql='select *from account where acctid=%s and money>=%s'%(acctid,mon) self.cursor.execute(selm_sql) rs=self.cursor.fetchone() try: len(rs) except: raise Exception def rd_mon(self,acctid,mon): rm_sql=' update account set money=money-%s where acctid=%s'%(mon,acctid) self.cursor.execute(rm_sql) if self.cursor.rowcount != 1: raise Exception def add_mon(self,acctid,mon): add_sql=' update account set money=money+%s where acctid=%s'%(mon,acctid) self.cursor.execute(add_sql) if self.cursor.rowcount != 1: raise Exception def transfor(self,srid,trid,mon): try: self.is_ava(srid) self.is_ava(trid) self.mon_ava(srid,mon) self.rd_mon(srid,mon) self.add_mon(trid,mon) self.con.commit() except: self.con.rollback() finally: self.cursor.close() self.con.close() if __name__=='__main__': sr_id=sys.argv[1] tr_id=sys.argv[2] dt_money=sys.argv[3] con=pymysql.Connect(host='xxx.xxx.xx.xx',port=3306,db='pytest',user='root', passwd='xxxxx',charset='utf8') tr_obj=TransforMoney(con) tr_obj.transfor(sr_id,tr_id,dt_money)
把所有方法都封裝到一個類里,transfor方法里同樣是事務操作,前面也說道過 __name__這個內置屬性,這個程序如果直接運行的話 __name__就等於__main,那么此時if __name__=='__main__' 就成立,即這句話相當於該程序的入口。
3:下面看第三種方式 模塊化
# -*- coding: utf-8 -*- """ Created on Tue Jun 6 11:45:42 2017 @author: A """ import sys import pymysql import temp2 sr_id=sys.argv[1] tr_id=sys.argv[2] dt_money=sys.argv[3] con=pymysql.Connect(host='xxx.xxx.xx.xx',port=3306,db='pytest',user='root', passwd='xxxxx',charset='utf8') tr_obj=temp2.TransforMoney(con) tr_obj.transfor(sr_id,tr_id,dt_money)
是不是很短,沒錯,把上述第二種方式的程序保存為temp2.py ,在該程序里直接import temp2 即可調用temp2.py的類的方法,注意此時temp2.py里的__name__ 就不等於__main__了 而是等於 temp.
對了,以上的連接 host 和 passwd 我都用xxx 來表示了,因為是我個人的服務器不便於公開,實際中大家改成自己的就可以了。