自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Python操作MySQL存儲,這些你都會了嗎?

存儲 存儲軟件
在Python 2中,連接MySQL的庫大多是使用MySQLdb,但是此庫的官方并不支持Python 3,所以這里推薦使用的庫是PyMySQL。

 在Python 2中,連接MySQL的庫大多是使用MySQLdb,但是此庫的官方并不支持Python 3,所以這里推薦使用的庫是PyMySQL。

[[265766]]

本節(jié)中,我們就來講解使用PyMySQL操作MySQL數(shù)據(jù)庫的方法。

1. 準備工作

在開始之前,請確保已經(jīng)安裝好了MySQL數(shù)據(jù)庫并保證它能正常運行,而且需要安裝好PyMySQL庫。

2. 連接數(shù)據(jù)庫

這里,首先嘗試連接一下數(shù)據(jù)庫。假設(shè)當前的MySQL運行在本地,用戶名為root,密碼為123456,運行端口為3306。這里利用PyMySQL先連接MySQL,然后創(chuàng)建一個新的數(shù)據(jù)庫,名字叫作spiders,代碼如下:

  1. import pymysql 
  2.  
  3. db = pymysql.connect(host='localhost',user='root'password='123456', port=3306) 
  4. cursor = db.cursor() 
  5. cursor.execute('SELECT VERSION()'
  6. data = cursor.fetchone() 
  7. print('Database version:', data) 
  8. cursor.execute("CREATE DATABASE spiders DEFAULT CHARACTER SET utf8"
  9. db.close() 

運行結(jié)果如下:

  1. Database version: ('5.6.22',) 

這里通過PyMySQL的connect()方法聲明一個MySQL連接對象db,此時需要傳入MySQL運行的host(即IP)。由于MySQL在本地運行,所以傳入的是localhost。如果MySQL在遠程運行,則傳入其公網(wǎng)IP地址。后續(xù)的參數(shù)user即用戶名,password即密碼,port即端口(默認為3306)。

連接成功后,需要再調(diào)用cursor()方法獲得MySQL的操作游標,利用游標來執(zhí)行SQL語句。這里我們執(zhí)行了兩句SQL,直接用execute()方法執(zhí)行即可。***句SQL用于獲得MySQL的當前版本,然后調(diào)用fetchone()方法獲得***條數(shù)據(jù),也就得到了版本號。第二句SQL執(zhí)行創(chuàng)建數(shù)據(jù)庫的操作,數(shù)據(jù)庫名叫作spiders,默認編碼為UTF-8。由于該語句不是查詢語句,所以直接執(zhí)行后就成功創(chuàng)建了數(shù)據(jù)庫spiders。接著,再利用這個數(shù)據(jù)庫進行后續(xù)的操作。

3. 創(chuàng)建表

一般來說,創(chuàng)建數(shù)據(jù)庫的操作只需要執(zhí)行一次就好了。當然,我們也可以手動創(chuàng)建數(shù)據(jù)庫。以后,我們的操作都在spiders數(shù)據(jù)庫上執(zhí)行。

創(chuàng)建數(shù)據(jù)庫后,在連接時需要額外指定一個參數(shù)db。

接下來,新創(chuàng)建一個數(shù)據(jù)表students,此時執(zhí)行創(chuàng)建表的SQL語句即可。這里指定3個字段,結(jié)構(gòu)如下所示。

創(chuàng)建該表的示例代碼如下:

  1. import pymysql 
  2.  
  3. db = pymysql.connect(host='localhost'user='root'password='123456', port=3306, db='spiders'
  4. cursor = db.cursor() 
  5. sql = 'CREATE TABLE IF NOT EXISTS students (id VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, age INT NOT NULL, PRIMARY KEY (id))' 
  6. cursor.execute(sql) 
  7. db.close() 

運行之后,我們便創(chuàng)建了一個名為students的數(shù)據(jù)表。

當然,為了演示,這里只指定了最簡單的幾個字段。實際上,在爬蟲過程中,我們會根據(jù)爬取結(jié)果設(shè)計特定的字段。

4. 插入數(shù)據(jù)

下一步就是向數(shù)據(jù)庫中插入數(shù)據(jù)了。例如,這里爬取了一個學生信息,學號為20120001,名字為Bob,年齡為20,那么如何將該條數(shù)據(jù)插入數(shù)據(jù)庫呢?示例代碼如下:

  1. import pymysql 
  2.  
  3. id = '20120001' 
  4. user = 'Bob' 
  5. age = 20 
  6.  
  7. db = pymysql.connect(host='localhost'user='root'password='123456', port=3306, db='spiders'
  8. cursor = db.cursor() 
  9. sql = 'INSERT INTO students(id, name, age) values(%s, %s, %s)' 
  10. try: 
  11.     cursor.execute(sql, (id, user, age)) 
  12.     db.commit() 
  13. except
  14.     db.rollback() 
  15. db.close() 

這里首先構(gòu)造了一個SQL語句,其Value值沒有用字符串拼接的方式來構(gòu)造,如:

  1. sql = 'INSERT INTO students(id, name, age) values(' + id + ', ' + name + ', ' + age + ')' 

這樣的寫法煩瑣而且不直觀,所以我們選擇直接用格式化符%s來實現(xiàn)。有幾個Value寫幾個%s,我們只需要在execute()方法的***個參數(shù)傳入該SQL語句,Value值用統(tǒng)一的元組傳過來就好了。這樣的寫法既可以避免字符串拼接的麻煩,又可以避免引號沖突的問題。

之后值得注意的是,需要執(zhí)行db對象的commit()方法才可實現(xiàn)數(shù)據(jù)插入,這個方法才是真正將語句提交到數(shù)據(jù)庫執(zhí)行的方法。對于數(shù)據(jù)插入、更新、刪除操作,都需要調(diào)用該方法才能生效。

接下來,我們加了一層異常處理。如果執(zhí)行失敗,則調(diào)用rollback()執(zhí)行數(shù)據(jù)回滾,相當于什么都沒有發(fā)生過。

這里涉及事務(wù)的問題。事務(wù)機制可以確保數(shù)據(jù)的一致性,也就是這件事要么發(fā)生了,要么沒有發(fā)生。比如插入一條數(shù)據(jù),不會存在插入一半的情況,要么全部插入,要么都不插入,這就是事務(wù)的原子性。另外,事務(wù)還有3個屬性——一致性、隔離性和持久性。這4個屬性通常稱為ACID特性,具體如下表所示。

  1. try: 
  2.     cursor.execute(sql) 
  3.     db.commit() 
  4. except
  5.     db.rollback() 

這樣便可以保證數(shù)據(jù)的一致性。這里的commit()和rollback()方法就為事務(wù)的實現(xiàn)提供了支持。

上面數(shù)據(jù)插入的操作是通過構(gòu)造SQL語句實現(xiàn)的,但是很明顯,這有一個極其不方便的地方,比如突然增加了性別字段gender,此時SQL語句就需要改成:

  1. INSERT INTO students(id, name, age, gender) values(%s, %s, %s, %s) 

相應(yīng)的元組參數(shù)則需要改成:

  1. (id, name, age, gender) 

這顯然不是我們想要的。在很多情況下,我們要達到的效果是插入方法無需改動,做成一個通用方法,只需要傳入一個動態(tài)變化的字典就好了。比如,構(gòu)造這樣一個字典:

  1.     'id''20120001'
  2.     'name''Bob'
  3.     'age': 20 

然后SQL語句會根據(jù)字典動態(tài)構(gòu)造,元組也動態(tài)構(gòu)造,這樣才能實現(xiàn)通用的插入方法。所以,這里我們需要改寫一下插入方法:

  1. data = { 
  2.     'id''20120001'
  3.     'name''Bob'
  4.     'age': 20 
  5. table = 'students' 
  6. keys = ', '.join(data.keys()) 
  7. values = ', '.join(['%s'] * len(data)) 
  8. sql = 'INSERT INTO {table}({keys}) VALUES ({values})'.format(table=table, keys=keys, values=values
  9. try: 
  10.    if cursor.execute(sql, tuple(data.values())): 
  11.        print('Successful'
  12.        db.commit() 
  13. except
  14.     print('Failed'
  15.     db.rollback() 
  16. db.close() 

這里我們傳入的數(shù)據(jù)是字典,并將其定義為data變量。表名也定義成變量table。接下來,就需要構(gòu)造一個動態(tài)的SQL語句了。

首先,需要構(gòu)造插入的字段id、name和age。這里只需要將data的鍵名拿過來,然后用逗號分隔即可。所以', '.join(data.keys())的結(jié)果就是id, name, age,然后需要構(gòu)造多個%s當作占位符,有幾個字段構(gòu)造幾個即可。比如,這里有三個字段,就需要構(gòu)造%s, %s, %s。這里首先定義了長度為1的數(shù)組['%s'],然后用乘法將其擴充為['%s', '%s', '%s'],再調(diào)用join()方法,最終變成%s, %s, %s。***,我們再利用字符串的format()方法將表名、字段名和占位符構(gòu)造出來。最終的SQL語句就被動態(tài)構(gòu)造成了:

  1. INSERT INTO students(id, name, age) VALUES (%s, %s, %s) 

***,為execute()方法的***個參數(shù)傳入sql變量,第二個參數(shù)傳入data的鍵值構(gòu)造的元組,就可以成功插入數(shù)據(jù)了。

如此以來,我們便實現(xiàn)了傳入一個字典來插入數(shù)據(jù)的方法,不需要再去修改SQL語句和插入操作了。

5. 更新數(shù)據(jù)

數(shù)據(jù)更新操作實際上也是執(zhí)行SQL語句,最簡單的方式就是構(gòu)造一個SQL語句,然后執(zhí)行:

  1. sql = 'UPDATE students SET age = %s WHERE name = %s' 
  2. try: 
  3.    cursor.execute(sql, (25, 'Bob')) 
  4.    db.commit() 
  5. except
  6.    db.rollback() 
  7. db.close() 

這里同樣用占位符的方式構(gòu)造SQL,然后執(zhí)行execute()方法,傳入元組形式的參數(shù),同樣執(zhí)行commit()方法執(zhí)行操作。如果要做簡單的數(shù)據(jù)更新的話,完全可以使用此方法。

但是在實際的數(shù)據(jù)抓取過程中,大部分情況下需要插入數(shù)據(jù),但是我們關(guān)心的是會不會出現(xiàn)重復數(shù)據(jù),如果出現(xiàn)了,我們希望更新數(shù)據(jù)而不是重復保存一次。另外,就像前面所說的動態(tài)構(gòu)造SQL的問題,所以這里可以再實現(xiàn)一種去重的方法,如果數(shù)據(jù)存在,則更新數(shù)據(jù);如果數(shù)據(jù)不存在,則插入數(shù)據(jù)。另外,這種做法支持靈活的字典傳值。示例如下:

  1. data = { 
  2.     'id''20120001'
  3.     'name''Bob'
  4.     'age': 21 
  5.  
  6. table = 'students' 
  7. keys = ', '.join(data.keys()) 
  8. values = ', '.join(['%s'] * len(data)) 
  9.  
  10. sql = 'INSERT INTO {table}({keys}) VALUES ({values}) ON DUPLICATE KEY UPDATE'.format(table=table, keys=keys, values=values
  11. update = ','.join([" {key} = %s".format(key=keyfor key in data]) 
  12. sql += update 
  13. try: 
  14.     if cursor.execute(sql, tuple(data.values())*2): 
  15.         print('Successful'
  16.         db.commit() 
  17. except
  18.     print('Failed'
  19.     db.rollback() 
  20. db.close() 

這里構(gòu)造的SQL語句其實是插入語句,但是我們在后面加了ON DUPLICATE KEY UPDATE。這行代碼的意思是如果主鍵已經(jīng)存在,就執(zhí)行更新操作。比如,我們傳入的數(shù)據(jù)id仍然為20120001,但是年齡有所變化,由20變成了21,此時這條數(shù)據(jù)不會被插入,而是直接更新id為20120001的數(shù)據(jù)。完整的SQL構(gòu)造出來是這樣的:

  1. INSERT INTO students(id, name, age) VALUES (%s, %s, %s) ON DUPLICATE KEY UPDATE id = %s, name = %s, age = %s 

這里就變成了6個%s。所以在后面的execute()方法的第二個參數(shù)元組就需要乘以2變成原來的2倍。

如此一來,我們就可以實現(xiàn)主鍵不存在便插入數(shù)據(jù),存在則更新數(shù)據(jù)的功能了。

6. 刪除數(shù)據(jù)

刪除操作相對簡單,直接使用DELETE語句即可,只是需要指定要刪除的目標表名和刪除條件,而且仍然需要使用db的commit()方法才能生效。示例如下:

  1. table = 'students' 
  2. condition = 'age > 20' 
  3.  
  4. sql = 'DELETE FROM  {table} WHERE {condition}'.format(table=table, condition=condition) 
  5. try: 
  6.     cursor.execute(sql) 
  7.     db.commit() 
  8. except
  9.     db.rollback() 
  10.  
  11. db.close() 

因為刪除條件有多種多樣,運算符有大于、小于、等于、LIKE等,條件連接符有AND、OR等,所以不再繼續(xù)構(gòu)造復雜的判斷條件。這里直接將條件當作字符串來傳遞,以實現(xiàn)刪除操作。

7. 查詢數(shù)據(jù)

說完插入、修改和刪除等操作,還剩下非常重要的一個操作,那就是查詢。查詢會用到SELECT語句,示例如下:

  1. sql = 'SELECT * FROM students WHERE age >= 20' 
  2.  
  3. try: 
  4.     cursor.execute(sql) 
  5.     print('Count:'cursor.rowcount) 
  6.     one = cursor.fetchone() 
  7.     print('One:', one) 
  8.     results = cursor.fetchall() 
  9.     print('Results:', results) 
  10.     print('Results Type:', type(results)) 
  11.     for row in results: 
  12.         print(row) 
  13. except
  14.     print('Error'

運行結(jié)果如下:

  1. Count: 4 
  2. One: ('20120001''Bob', 25) 
  3. Results: (('20120011''Mary', 21), ('20120012''Mike', 20), ('20120013''James', 22)) 
  4. Results Type: <class 'tuple'
  5. ('20120011''Mary', 21) 
  6. ('20120012''Mike', 20) 
  7. ('20120013''James', 22) 

這里我們構(gòu)造了一條SQL語句,將年齡20歲及以上的學生查詢出來,然后將其傳給execute()方法。注意,這里不再需要db的commit()方法。接著,調(diào)用cursor的rowcount屬性獲取查詢結(jié)果的條數(shù),當前示例中是4條。

然后我們調(diào)用了fetchone()方法,這個方法可以獲取結(jié)果的***條數(shù)據(jù),返回結(jié)果是元組形式,元組的元素順序跟字段一一對應(yīng),即***個元素就是***個字段id,第二個元素就是第二個字段name,以此類推。隨后,我們又調(diào)用了fetchall()方法,它可以得到結(jié)果的所有數(shù)據(jù)。然后將其結(jié)果和類型打印出來,它是二重元組,每個元素都是一條記錄,我們將其遍歷輸出出來。

但是這里需要注意一個問題,這里顯示的是3條數(shù)據(jù)而不是4條,fetchall()方法不是獲取所有數(shù)據(jù)嗎?這是因為它的內(nèi)部實現(xiàn)有一個偏移指針用來指向查詢結(jié)果,最開始偏移指針指向***條數(shù)據(jù),取一次之后,指針偏移到下一條數(shù)據(jù),這樣再取的話,就會取到下一條數(shù)據(jù)了。我們最初調(diào)用了一次fetchone()方法,這樣結(jié)果的偏移指針就指向下一條數(shù)據(jù),fetchall()方法返回的是偏移指針指向的數(shù)據(jù)一直到結(jié)束的所有數(shù)據(jù),所以該方法獲取的結(jié)果就只剩3個了。

此外,我們還可以用while循環(huán)加fetchone()方法來獲取所有數(shù)據(jù),而不是用fetchall()全部一起獲取出來。fetchall()會將結(jié)果以元組形式全部返回,如果數(shù)據(jù)量很大,那么占用的開銷會非常高。因此,推薦使用如下方法來逐條取數(shù)據(jù):

  1. sql = 'SELECT * FROM students WHERE age >= 20' 
  2. try: 
  3.     cursor.execute(sql) 
  4.     print('Count:'cursor.rowcount) 
  5.     row = cursor.fetchone() 
  6.     while row: 
  7.         print('Row:', row) 
  8.         row = cursor.fetchone() 
  9. except
  10.     print('Error'

這樣每循環(huán)一次,指針就會偏移一條數(shù)據(jù),隨用隨取,簡單高效。

本節(jié)中,我們介紹了如何使用PyMySQL操作MySQL數(shù)據(jù)庫以及一些SQL語句的構(gòu)造方法。

責任編輯:武曉燕 來源: 今日頭條
相關(guān)推薦

2018-04-26 16:35:44

PythonMySQL存儲

2021-12-14 18:20:23

Github技巧前端

2023-11-27 11:42:46

DjangoPython

2023-12-24 22:30:05

LambdaJava函數(shù)

2024-07-04 09:39:40

Go語言MongoDB

2022-12-06 07:53:33

MySQL索引B+樹

2023-05-05 06:54:07

MySQL數(shù)據(jù)查詢

2023-03-26 22:31:29

2024-08-19 10:24:14

2022-12-08 10:49:43

2024-10-18 10:35:10

2023-11-01 07:28:31

MySQL日志維護

2021-12-01 07:19:44

C# Npoi Excel

2024-02-27 08:39:19

RustJSON字符串

2022-11-02 10:21:41

K8s pod運維

2022-11-03 08:16:33

MySQL·窗口函數(shù)

2023-09-12 07:26:46

2023-05-24 08:14:55

2024-01-02 12:05:26

Java并發(fā)編程

2023-08-01 12:51:18

WebGPT機器學習模型
點贊
收藏

51CTO技術(shù)棧公眾號