一懈糯、安裝MySQL
MySQL Community Downloads
windows10上安裝mysql(詳細(xì)步驟)
二污它、為Python安裝一個(gè)MySQL數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序
MySQL-Connector/Python無(wú)法用pip安裝,手動(dòng)安裝MySQL-Connector/Python驅(qū)動(dòng)程序:
選擇源碼(Source Code)
在頁(yè)面最下方找到平臺(tái)獨(dú)立(Platform Independent)的壓縮包
(Windows下載ZIP文件移盆,Linux和Mac OS可下載GZ)
下載解壓為文件夾mysql-connector-python-8.0.12,作為管理員打開(kāi)終端窗口康愤,需要在mysql-connector-python-8.0.12中執(zhí)行以下命令:
py -3 setup.py install
Linux或Mac OS半开,則使用以下命令:
sudo -H python3 setup.py install
建議環(huán)境PATH配置修改鉴未!
三.創(chuàng)建Web應(yīng)用的數(shù)據(jù)庫(kù)和表
使用數(shù)據(jù)庫(kù) 具體使用Python的DB-API (如何解決error2003枢冤,error1064,error1045)
啟動(dòng)MySQL控制臺(tái)铜秆,
要作為MySQL數(shù)據(jù)庫(kù)管理員登錄(使用根目錄ID
注意:
在安裝mysql5.7版本時(shí)淹真,經(jīng)常會(huì)遇到mysql -u root -p直接回車(chē)登陸不上的情況,原因在于5.7版本在安裝時(shí)自動(dòng)給了一個(gè)隨機(jī)密碼连茧,坑爹的是在init步驟的時(shí)候不像linux系統(tǒng)會(huì)給出命令行提示核蘸,需要手動(dòng)在mysql目錄下搜索*.err,以文本形式打開(kāi)才能看到如下內(nèi)容:
016-02-25T15:09:43.033062Z 1 [Note] A temporary password is generated for root@localhost:>mso<k70mrWe
紅色字母即為第一次的登陸密碼啸驯,記得加雙引號(hào)客扎。)
下面是啟動(dòng)控制臺(tái)的命令:
mysql -u root -p
創(chuàng)建一個(gè)數(shù)據(jù)庫(kù),名為vsearchlogDB
以下為創(chuàng)建數(shù)據(jù)庫(kù)的命令:
mysql> create database vsearchlogDB;
參考head first python創(chuàng)建新的用戶(hù)和口令失敗罚斗,如下
mysql> grant all on vsearchlogDB.* to 'vsearch' identified by 'vsearchpasswd';
于是出現(xiàn)錯(cuò)誤error1064:
解決方法:create user語(yǔ)句創(chuàng)建一個(gè)用戶(hù)徙鱼,然后再grant權(quán)限,成功针姿。
mysql> create user vsearch identified by 'vsearchpasswd';
mysql> grant all on vsearchlogDB.* to 'vsearch';
推測(cè)是mysql8以后不允許直接建立用戶(hù)并給權(quán)限的操作了袱吆。
而后用新創(chuàng)建的vsearch用戶(hù)登錄:
mysql -u vsearch -p vsearchlogDB
卻又出現(xiàn)錯(cuò)誤error1045:
解決方案:mysql -u root -p 直接回車(chē)兩次
use +數(shù)據(jù)庫(kù)名,即可
然后就可以存放數(shù)據(jù):
可以看到log表已經(jīng)存在距淫,而且結(jié)構(gòu)符合這個(gè)Web應(yīng)用的日志記錄需要绞绒,輸入quit退出控制臺(tái)。
Python中的BD-API
?????? 在沒(méi)有DB-API之前榕暇,接口程序混亂蓬衡。具體的就是說(shuō)喻杈,由于最底層用的數(shù)據(jù)庫(kù)技術(shù)不同,所以在應(yīng)用程序?qū)泳鸵槍?duì)特定的數(shù)據(jù)庫(kù)進(jìn)行特定的編碼狰晚,如果要改變一個(gè)版本所使用的底層數(shù)據(jù)庫(kù)筒饰,那么之前編寫(xiě)的應(yīng)用程序中關(guān)于數(shù)據(jù)庫(kù)的代碼也要進(jìn)行相應(yīng)的改變。
python DB-API:python訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)的統(tǒng)一接口規(guī)范家肯。
?????? 這里有一個(gè)約定:程序員使用python與任何底層數(shù)據(jù)庫(kù)交互時(shí)都使用DB-API龄砰,而不論這個(gè)數(shù)據(jù)庫(kù)技術(shù)具體是什么盟猖,這么做是因?yàn)樘忠拢抿?qū)動(dòng)程序,程序員無(wú)需了解與數(shù)據(jù)庫(kù)具體API交互的底層細(xì)節(jié)式镐,因?yàn)镈B-API在代碼與驅(qū)動(dòng)程序之間提供了一個(gè)抽象層反镇,這里的想法是:通過(guò)使用DB-API編程,可以根據(jù)需要替換掉底層數(shù)據(jù)庫(kù)技術(shù)娘汞,而無(wú)須丟棄現(xiàn)有的代碼歹茶。
1、定義連接屬性
連接到MySQL服務(wù)器時(shí)需要4部分信息:
(1)運(yùn)行MySQL服務(wù)器的計(jì)算機(jī)(稱(chēng)為主機(jī))的IP地址/主機(jī)名你弦;
(2)要使用的用戶(hù)ID惊豺;
(3)與用戶(hù)ID關(guān)聯(lián)的口令;
(4)這一用戶(hù)ID想要交互的數(shù)據(jù)庫(kù)名禽作。
>>> dbconfig = {'host':? '127.0.0.1',???????????????
? #服務(wù)器在我們本地計(jì)算機(jī)上運(yùn)行尸昧。所以“host”使用localhost IP地址。
'user':? 'vsearch',
#這一章前面創(chuàng)建的“vsearch”用戶(hù)ID賦給“user”鍵旷偿。
'password':? 'vseacrh',
“password”鍵賦為我們的用戶(hù)ID相應(yīng)的正確口令烹俗。
'database':? 'vsearchlogDB', }
數(shù)據(jù)庫(kù)名(這里就是“vsearchlogDB”)賦至“database”鍵。
2萍程、導(dǎo)入數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序
>>> import mysql.connector
3幢妄、建立與MySQL服務(wù)器的一個(gè)連接
conn = mysql.connector.connect(**dbconfig)
(**)記法告訴connect函數(shù)用一個(gè)變量提供了參數(shù)字典,如果看到這種記法茫负,connect函數(shù)會(huì)把這個(gè)字典展開(kāi)為4個(gè)單獨(dú)的參數(shù)蕉鸳,然后在connect函數(shù)中使用這些參數(shù)來(lái)建立連接。
4忍法、打開(kāi)一個(gè)游標(biāo)
要向數(shù)據(jù)庫(kù)發(fā)送SQL命令(通過(guò)剛才打開(kāi)的連接)以及從數(shù)據(jù)庫(kù)接收結(jié)果置吓,我們需要一個(gè)游標(biāo),可以把游標(biāo)理解成數(shù)據(jù)庫(kù)中文件的句柄缔赠。
創(chuàng)建游標(biāo)很簡(jiǎn)單:只需要調(diào)用cursor方法衍锚,每個(gè)連接對(duì)象都有這個(gè)方法。
接下來(lái)需要一個(gè)翻譯機(jī)嗤堰,也就是游標(biāo)(cursor)戴质,代碼如下:
>>> cursor=conn.cursor()
然后就可以用這個(gè)游標(biāo)度宦,使用SQL語(yǔ)言與服務(wù)器端的數(shù)據(jù)庫(kù)通信了。
前面我們所做的這些操作告匠,在無(wú)論使用什么數(shù)據(jù)庫(kù)時(shí)戈抄,都是通用的。只是連接屬性可能不同而已后专。
5划鸽、完成SQL查詢(xún)
可以利用cursor變量向MySQL發(fā)送SQL查詢(xún),以及獲取MySQL處理查詢(xún)生成的結(jié)果戚哎,我認(rèn)為的是這個(gè)跟ajax中的request請(qǐng)求對(duì)象很像裸诽。
_SQL = """show tables"""
cursor.execute(_SQL);
一般用三重雙引號(hào)來(lái)編寫(xiě)要發(fā)送給數(shù)據(jù)庫(kù)服務(wù)器的SQL,之所以使用三重雙引號(hào),是因?yàn)槿仉p引號(hào)可以暫定不啟用python解釋器中的“行末即語(yǔ)句結(jié)束的規(guī)則”型凳。
執(zhí)行cursor.execute()命令時(shí)丈冬,這個(gè)SQL查詢(xún)會(huì)被發(fā)送到MySQL的服務(wù)器,它會(huì)執(zhí)行這個(gè)查詢(xún)(假設(shè)正確)甘畅,不過(guò)結(jié)果并不會(huì)立即顯示埂蕊,必須要請(qǐng)求結(jié)果。
注意疏唾,SQL代碼是存在一個(gè)字符串中的蓄氧,這樣python就不會(huì)試圖去理解這句代碼的意思,而是老老實(shí)實(shí)通過(guò)cursor把這句代碼傳到服務(wù)器端槐脏,并運(yùn)行喉童。
然而它并不會(huì)返回一個(gè)結(jié)果,需要我們自己去請(qǐng)求結(jié)果准给。
請(qǐng)求結(jié)果有三種方式:
fetchone:請(qǐng)求一行結(jié)果泄朴;
fetchmany:請(qǐng)求指定行結(jié)果;
feychall:請(qǐng)求所有結(jié)果露氮。
我們選擇請(qǐng)求所有結(jié)果祖灰。代碼如下:
>>> res=cursor.fetchall()
>>> res
[('log', ) ]
這里要特別注意點(diǎn)是:fetchall()方法,它返回的是客戶(hù)端緩沖區(qū)現(xiàn)在還沒(méi)有被影響的記錄畔规。注意返回的是一個(gè)列表局扶,列表中的元素是元組。也就是說(shuō)叁扫。fetchall返回值的類(lèi)型一定是一個(gè)元組列表三妈,即使只有一個(gè)元素也不例外。由于我們?cè)?.3中只建了一張名為log的表莫绣,因此這里只有l(wèi)og一個(gè)結(jié)果畴蒲。
如果想要查看表中的內(nèi)容怎么辦呢?用SQL的describe語(yǔ)句对室。如下:
>>> _SQL="""describe log"""
>>> cursor.execute(_SQL)
>>> res=cursor.fetchall()
>>> res
[('id', b'int', 'NO', 'PRI', None, 'auto_increment'), ('ts', b'timestamp', 'YES', '', b'CURRENT_TIMESTAMP', 'DEFAULT_GENERATED'), ('phrase', b'varchar(128)', 'NO', '', None, ''), ('letters', b'varchar(32)', 'NO', '', None, ''), ('ip', b'varchar(16)', 'NO', '', None, ''), ('browser_string', b'varchar(256)', 'NO', '', None, ''), ('results', b'varchar(64)', 'NO', '', None, '')]
感覺(jué)有點(diǎn)亂模燥。但還是可以看出咖祭,返回的仍是一個(gè)列表(最外面是方括號(hào)[]),列表的每個(gè)元素都是元組(次外層是括號(hào)())蔫骂,元組元素為字符串么翰,若元組中元素為空,則元組元素不顯示辽旋。
表中每一行對(duì)應(yīng)一個(gè)元組浩嫌。這樣來(lái)看,按行輸出比較合適补胚,效果如下:
>>> for row in res:
??????? print(row)
還不錯(cuò)码耐。res中就保存了log表中的所有數(shù)據(jù)。
下面來(lái)看如何在表中添加數(shù)據(jù)糖儡。使用SQL的insert語(yǔ)句伐坏。如下:
>>> _SQL="""insert into log
? ? ? ? (phrase,letters,ip,browser_string,results)
? ? ? ? values
? ? ? ? ('hitch-hicker','aeiou','127.0.0.1','Firefox',"{'e','i'}")"""
>>> cursor.execute(_SQL)
?????? 然而這種插入操作很蠢怔匣,為什么呢握联?觀(guān)察_SQL這個(gè)變量,它是一句SQL代碼每瞒,對(duì)于insert操作金闽,每次都要重新生成一條代碼來(lái)插入不同的數(shù)據(jù),這太低效了剿骨,如果有一種方法代芜,可以將insert語(yǔ)句與待插入內(nèi)容分開(kāi),要用的時(shí)候再合并浓利,也就是說(shuō)挤庇,把insert語(yǔ)句看成一個(gè)函數(shù),可重用贷掖,這就好了嫡秕。有這種方法。代碼如下:
>>> _SQL="""insert into log
? ? ? ? (phrase,letters,ip,browser_string,results)
? ? ? ? values
? ? ? ? (%s,%s,%s,%s,%s)"""
>>> cursor.execute(_SQL,('hitch-hiker','xyz','127.0.0.1','Safari','set()'))
?????? _SQL并沒(méi)有具體說(shuō)明要插入的內(nèi)容苹威,而是用五個(gè)占位符%s來(lái)進(jìn)行指定昆咽。在實(shí)際應(yīng)用時(shí),只需要在execute后加入一個(gè)元組牙甫,元組內(nèi)容對(duì)應(yīng)占位符即可掷酗。
?????? 然后查看表中內(nèi)容是否添加成功。使用select命令窟哺。但很有可能select無(wú)法返回任何數(shù)據(jù)泻轰。因?yàn)椋?dāng)使用insert操作時(shí)且轨,由于寫(xiě)數(shù)據(jù)庫(kù)是一個(gè)開(kāi)銷(xiāo)很大的操作浮声,所以數(shù)據(jù)庫(kù)系統(tǒng)會(huì)緩存insert亩鬼,然后再一次性應(yīng)用全部的insert。這帶來(lái)的問(wèn)題就是阿蝶,剛剛插入的數(shù)據(jù)可能訪(fǎng)問(wèn)不到雳锋。但是可以通過(guò)事務(wù)提交(conn.commit())來(lái)強(qiáng)制數(shù)據(jù)庫(kù)系統(tǒng)將所有可能緩存的數(shù)據(jù)全部提交到數(shù)據(jù)庫(kù)表中,這樣既可解決訪(fǎng)問(wèn)不到的問(wèn)題羡洁。
注意describe是用于描述一個(gè)表的玷过,它描述了表的屬性,而不管表的內(nèi)容筑煮;select則用于顯示表的內(nèi)容辛蚊,而不顯示表的屬性。代碼如下:
>>> conn.commit()
>>> _SQL="""select * from log"""
>>> cursor.execute(_SQL)
>>> for row in cursor.fetchall():
??????? print(row)
得到結(jié)果:
6真仲、關(guān)閉游標(biāo)和連接
數(shù)據(jù)提交到數(shù)據(jù)庫(kù)表中后袋马,要進(jìn)行清理,關(guān)閉游標(biāo)和連接秸应。
>>> cursor.close()
True
>>> conn.close()
這是因?yàn)閿?shù)據(jù)庫(kù)系統(tǒng)是一組有限的資源虑凛,不關(guān)閉會(huì)導(dǎo)致資源嚴(yán)重浪費(fèi),其它用戶(hù)無(wú)法訪(fǎng)問(wèn)软啼。
四桑谍、創(chuàng)建代碼處理Web應(yīng)用的數(shù)據(jù)庫(kù)和表
下面是回顧最近做的一個(gè)項(xiàng)目中關(guān)于數(shù)據(jù)庫(kù)連接的源碼:
#定義你的連接屬性
dbconfig = {"host": "127.0.0.1",
"user": "vsearch",
"password": "vsearch",
"database": "vsearchlogDB",
}
#導(dǎo)入數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序
import mysql.connector
#建立一個(gè)連接并創(chuàng)建一個(gè)游標(biāo)
conn = mysql.connector.connect(**dbconfig)
cursor = conn.cursor()
#將查詢(xún)賦至一個(gè)字符串(注意5個(gè)占位符參數(shù))
_SQL = """insert into log
(phrase, letters, ip, browser_string, results)
values
(%s, %s, %s, %s, %s)"""
#將查詢(xún)發(fā)送到服務(wù)器,記得要為各個(gè)參數(shù)提供值(以元組的形式)
cursor.execute(_SQL, ("afeng", "jingjing", "127.0.0.1", "opera", "{'x', 'y'}"))
#強(qiáng)制要求數(shù)據(jù)庫(kù)寫(xiě)數(shù)據(jù)
conn.commit()
#從表獲然雠病(剛寫(xiě)入的)數(shù)據(jù)锣披,逐行顯示輸出。
_SQL = """select * from log"""
cursor.execute(_SQL)
for row in cursor.fetchall():
???? print(row)
#完成時(shí)進(jìn)行清理
cursor.close()
conn.close()
由于有了以上的鋪墊贿条,我們現(xiàn)在要實(shí)現(xiàn)以下功能:修改Webapp的log_request函數(shù)雹仿,讓它保存的數(shù)據(jù)不是存在一個(gè)txt里,而是存在SQL數(shù)據(jù)庫(kù)中整以。
原代碼如下:
deflog_request(req:'flask_request',res:str)->None:
??? withopen('vsearch.log','a')aslog:
??????? print(req.form,req.remote_addr,req.user_agent,res,file=log,sep='|')
修改之后胧辽,要實(shí)現(xiàn)與數(shù)據(jù)庫(kù)的連接,實(shí)現(xiàn)寫(xiě)入等功能悄蕾,其實(shí)蠻簡(jiǎn)單票顾,如下:
deflog_request(req:'flask_request',res:str)->None:
?????? dbconfig={'host':'127.0.0.1',
?????????????????????? 'user':'vsearch',
?????????????????????? 'password':'vsearchpasswd',
????????????????????? 'database':'vsearchlogDB',}
??? import mysql.connector
? ?? conn=mysql.connector.connect(**dbconfig)
? ?? cursor=conn.cursor()
??? _SQL="""insert into log
? ? ? ? ? ? ?? (phrase,letters,ip,browser_string,results)
? ? ? ? ? ? ? ? values
? ? ? ? ? ? ?? (%s,%s,%s,%s,%s)"""
? cursor.execute(_SQL, (req.form['phrase'],
????????????????????????????????????? req.form['letters'],
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? req.remote_addr,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? req.user_agent.browser,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??? res,))
? ?? conn.commit()
? ?? cursor.close()
? ?? conn.close()
?????? 有兩點(diǎn)要注意,其一帆调,是import的位置奠骄,不要在函數(shù)內(nèi)部;其二番刊,對(duì)于數(shù)據(jù)的寫(xiě)入含鳞,req.form是一個(gè)字典,有兩項(xiàng)芹务,一項(xiàng)是phrase蝉绷,即輸入鸭廷;一項(xiàng)是letters,即輸出熔吗。??????
???? 另外辆床,注意第四項(xiàng)寫(xiě)入的元素req.user_agent.browser,不再是整個(gè)瀏覽器串(存儲(chǔ)在req.user_agent)桅狠,我們只抽取出瀏覽器名讼载。
應(yīng)用新修改的vsearch4web.py:
C:\webapps> py -3 vsearch4web.py
現(xiàn)在我們發(fā)現(xiàn)了一個(gè)新的問(wèn)題:
對(duì)于那些可能會(huì)用到多次的功能,如建立連接中跌、斷開(kāi)連接等咨堤,是否可以實(shí)現(xiàn)重用呢?
記住“建立漩符、處理一喘、清理”模式!
如果每次修改SQL都需要這樣繁瑣的一步步建立和斷開(kāi)連接嗜暴,一點(diǎn)都不優(yōu)美凸克。聯(lián)想到之前的打開(kāi)-關(guān)閉文件,我們也可以用with來(lái)實(shí)現(xiàn)這一點(diǎn)灼伤。如下所示:
with UseDatabase(dbconfig) as cursor:
這是使用with版本的代碼触徐。但是還不能工作咪鲜,因?yàn)槲覀冞€沒(méi)有寫(xiě)Usedatabase這一函數(shù)的上下文管理器狐赡,這里看看就好。
使用上下文管理器需要?jiǎng)?chuàng)建類(lèi)疟丙,在下面幾章颖侄,我們將學(xué)習(xí)如何創(chuàng)建類(lèi)。