mysql事務

事務的四大特性(ACID)

  • 原子性(Atomicity)
  • 一致性(Consistency)
  • 隔離性(Isolation)
  • 持久性(Durability)

原子性:事務內執行的sql操做看成一個總體,要麼同時成功,要麼同時失敗回滾 一致性:強調的是數據的狀態,指的是數據庫從一個一致性狀態到另一個一致性狀態,打個比方,A有200,B有100,A轉100給B,那麼最後的一致性狀態是A有100,B有200,若是狀態是A有100,B仍是原來的100,那這就不符合數據的一致性 隔離性:一個事務所作的修改在最終提交之前,對其餘事務是不可見的,也就是說,A有200,B有100,A轉100,B加100,尚未提交的時候,又開啓了一個事物,此時看到的是A有200,B有100,也就是第一個事物沒有commit以前的狀態;還有一點就是說事物對某 行的某個字段進行加操做,那麼在沒有提交以前,其餘事物是不能修改這一行的這個字段的,由於mysql此時的行鎖被第一個事物拿到,commit以後纔會釋放 持久性:事物一旦進行了提交,那麼數據落盤,所作的修改會永久保存到數據庫mysql

事務的隔離級別

事務的隔離級別是爲了解決mysql併發問題的幾種控制手段。sql

事務的併發問題

一、髒讀:事務A讀取了事務B更新的數據,而後B回滾操做,那麼A讀取到的數據是髒數據 二、不可重複讀:事務 A 屢次讀取同一數據,事務 B 在事務A屢次讀取的過程當中,對數據做了更新並提交,致使事務A屢次讀取同一數據時,結果 不一致。 三、幻讀:系統管理員A將數據庫中全部學生的成績從具體分數改成ABCDE等級,可是系統管理員B就在這個時候插入了一條具體分數的記錄,當系統管理員A改結束後發現還有一條記錄沒有改過來,就好像發生了幻覺同樣,這就叫幻讀。 小結:不可重複讀的和幻讀很容易混淆,不可重複讀側重於修改,幻讀側重於新增或刪除。解決不可重複讀的問題只需鎖住知足條件的行,解決幻讀須要鎖表 <font color='red'>單條</font>修改數據的命令會自動的觸發事務,包括insert、update、delete。 而在SQL語句中有手動開啓事務的緣由是:能夠進行屢次數據的修改,若是成功一塊兒成功,不然一塊兒會滾到以前的數據.數據庫

4種隔離級別

Read Uncommitted(讀取未提交內容)

在該隔離級別,全部事務均可以看到其餘未提交事務的執行結果。本隔離級別不多用於實際應用,由於它的性能也不比其餘級別好多少。讀取未提交的數據,也被稱之爲髒讀(Dirty Read)。session

Read Committed(讀取提交內容)

這是大多數數據庫系統的默認隔離級別(但不是MySQL默認的)。它知足了隔離的簡單定義:一個事務只能看見已經提交事務所作的改變。,由於同一事務的其餘實例在該實例處理其間可能會有新的commit,因此同一select可能返回不一樣結果,這就是不可重複讀併發

Repeatable Read(可重讀)

這是MySQL的默認事務隔離級別,它確保同一事務的多個實例在併發讀取數據時,會看到一樣的數據行。不過理論上,這會致使另外一個棘手的問題:幻讀 (Phantom Read)。簡單的說,幻讀指當用戶讀取某一範圍的數據行時,另外一個事務又在該範圍內插入了新行,當用戶再讀取該範圍的數據行時,會發現有新的「幻影」 行。InnoDB和Falcon存儲引擎經過多版本併發控制(MVCC,Multiversion Concurrency Control)機制解決了該問題。性能

Serializable(可串行化)

這是最高的隔離級別,它經過強制事務排序,使之不可能相互衝突,從而解決幻讀問題。簡言之,它是在每一個讀的數據行上加上共享鎖。在這個級別,可能致使大量的超時現象和鎖競爭。測試

在測試的時候,把mysql事務級別設置成 Repeatable Read,一個事務往裏插數據,另外一個事務是看不到其餘事務插入的數據的,即讀的不是最新數據,咱們把這種現象也看做是幻讀fetch

查看和設置隔離級別

SELECT @@tx_isolation 設置mysql的隔離級別:set session transaction isolation level 設置事務隔離級別spa

pymysql

對於pymysql有幾個點須要注意線程

默認支持事務

pymysql默認開啓事務,從每次執行執行增刪改都須要最終commit就能知道。 經過pymysql增長數據但未提交時候,發現表的AUTO_INCREMENT是一直遞增的(說明數據庫已經收到插入指令了,就等着拍板呢),這是爲了解決併發的考量,而且若是回滾AUTO_INCREMENT並不會減小,而是一直遞增下去,這樣纔不會出錯。

cursor對象存放查詢的數據

import pymysql
conn = pymysql.connect(host='localhost', user='root', password="123456",database='test', port=3306, charset='utf8')
cur = conn.cursor()
cur.execute('select * from department')
Out[5]: 4
cur.fetchone()
Out[6]: (200, '技術')
cur.execute('select * from employee')
Out[7]: 18
cur.fetchone()
Out[8]: 
(1,
 'egon',
 'male',
 18,
 datetime.date(2017, 3, 1),
 '辦事處外交大使',
 None,
 7300.33,
 401,
 1)

經過上面咱們能夠發現,當咱們查詢的時候,取數據沒有取完就執行另外一條查詢語句,那麼先前的查詢結果會被覆蓋。也就是說執行了一條查詢語句,那麼就應該當即取出結果,不然拿着這個cursor去執行任何增刪改查操做,原來存儲的查詢數據都會被清掉

pymysql模塊的threadsafety = 1

若是在多個線程中的cursor共用一個conn鏈接,那麼就會報相似pymysql.err.InternalError: Packet sequence number wrong - got 45 expected 0的錯誤

  1. 每一個線程擁有本身的鏈接
  2. 全部線程共用一個鏈接池,須要考慮線程總數和鏈接池鏈接數上限的問題

pymysql遇到的幻讀

以前我開了兩個線程,一個線程取數據,一個線程往表插入數據,最終的結果是每次取得的數據都是同樣的,可是數據表確確實實是在不停地增長數據。這是由於數據庫的隔離級別形成的.解決辦法有兩個:

  1. 修改隔離級別
  2. 創建conn的時候加上autocommit=True參數
相關文章
相關標籤/搜索