mysql鎖怎么實現,mysql鎖的實現

一文詳解-MySQL 事務和鎖

當多個用戶訪問同一份數據時,一個用戶在更改數據的過程中,可能有其他用戶同時發起更改請求,為保證數據庫記錄的更新從一個一致性狀態變為另外一個一致性狀態,使用事務處理是非常必要的,事務具有以下四個特性:

創新互聯建站是一家專注于成都網站建設、網站設計與策劃設計,巨野網站建設哪家好?創新互聯建站做網站,專注于網站建設10余年,網設計領域的專業建站公司;建站業務涵蓋:巨野等地區。巨野做網站價格咨詢:028-86922220

MySQL 提供了多種事務型存儲引擎,如 InnoDB 和 BDB 等,而 MyISAM 不支持事務。為了支持事務,InnoDB 存儲引擎引入了與事務處理相關的 REDO 日志和 UNDO 日志,同時事務依賴于 MySQL 提供的鎖機制

事務執行時需要將執行的事務日志寫入日志文件,對應的文件為 REDO 日志。當每條 SQL 進行數據更新操作時,首先將 REDO 日志寫進日志緩沖區。當客戶端執行 COMMIT 命令提交時,日志緩沖區的內容將被刷新到磁盤,日志緩沖區的刷新方式或者時間間隔可以通過參數 innodb_flush_log_at_trx_commit 控制

REDO 日志對應磁盤上的 ib_logifleN 文件,該文件默認為 5MB,建議設置為 512MB,以便容納較大的事務。MySQL 崩潰恢復時會重新執行 REDO 日志的記錄,恢復最新數據,保證已提交事務的持久性

與 REDO 日志相反,UNDO 日志主要用于事務異常時的數據回滾,具體內容就是記錄數據被修改前的信息到 UNDO 緩沖區,然后在合適的時間將內容刷新到磁盤

假如由于系統錯誤或者 rollback 操作而導致事務回滾,可以根據 undo 日志回滾到沒修改前的狀態,保證未提交事務的原子性

與 REDO 日志不同的是,磁盤上不存在單獨的 UNDO 日志文件,所有的 UNDO 日志均存在表空間對應的 .ibd 數據文件中,即使 MySQL 服務啟動了獨立表空間

在 MySQL 中,可以使用 BEGIN 開始事務,使用 COMMIT 結束事務,中間可以使用 ROLLBACK 回滾事務。MySQL 通過 SET AUTOCOMMIT、START TRANSACTION、COMMIT 和 ROLLBACK 等語句支持本地事務

MySQL 定義了四種隔離級別,指定事務中哪些數據改變其他事務可見、哪些數據該表其他事務不可見。低級別的隔離級別可以支持更高的并發處理,同時占用的系統資源更少

InnoDB 系統級事務隔離級別可以使用以下語句設置:

查看系統級事務隔離級別:

InnoDB 會話級事務隔離級別可以使用以下語句設置:

查看會話級事務隔離級別:

在該隔離級別,所有事務都可以看到其他未提交事務的執行結果。讀取未提交的數據稱為臟讀(Dirty Read),即是:首先開啟 A 和 B 兩個事務,在 B 事務更新但未提交之前,A 事務讀取到了更新后的數據,但由于 B 事務回滾,導致 A 事務出現了臟讀現象

所有事務只能看見已經提交事務所做的改變,此級別可以解決臟讀,但也會導致不可重復讀(Nonrepeatable Read):首先開啟 A 和 B 兩個事務,A事務讀取了 B 事務的數據,在 B 事務更新并提交后,A 事務又讀取到了更新后的數據,此時就出現了同一 A 事務中的查詢出現了不同的查詢結果

MySQL 默認的事務隔離級別,能確保同一事務的多個實例在并發讀取數據時看到同樣的數據行,理論上會導致一個問題,幻讀(Phontom Read)。例如,第一個事務對一個表中的數據做了修改,這種修改會涉及表中的全部數據行,同時第二個事務也修改這個表中的數據,這次的修改是向表中插入一行新數據,此時就會發生操作第一個事務的用戶發現表中還有沒有修改的數據行

InnoDB 通過多版本并發控制機制(MVCC)解決了該問題:InnoDB 通過為每個數據行增加兩個隱含值的方式來實現,這兩個隱含值記錄了行的創建時間、過期時間以及每一行存儲時間發生時的系統版本號,每個查詢根據事務的版本號來查詢結果

通過強制事務排序,使其不可能相互沖突,從而解決幻讀問題。簡而言之,就是在每個讀的數據行上加上共享鎖實現,這個級別會導致大量的超時現象和鎖競爭,一般不推薦使用

為了解決數據庫并發控制問題,如走到同一時刻客戶端對同一張表做更新或者查詢操作,需要對并發操作進行控制,因此產生了鎖

共享鎖的粒度是行或者元組(多個行),一個事務獲取了共享鎖以后,可以對鎖定范圍內的數據執行讀操作

排他鎖的粒度與共享鎖相同,一個事務獲取排他鎖以后,可以對鎖定范圍內的數據執行寫操作

有兩個事務 A 和 B,如果事務 A 獲取了一個元組的共享鎖,事務 B 還可以立即獲取這個元組的共享鎖,但不能獲取這個元組的排他鎖,必須等到事務 A 釋放共享鎖之后。如果事務 A 獲取了一個元組的排他鎖,事務 B 不能立即獲取這個元組的共享鎖,也不能立即獲取這個元組的排他鎖,必須等到 A 釋放排他鎖之后

意向鎖是一種表鎖,鎖定的粒度是整張表,分為意向共享鎖和意向排他鎖。意向共享鎖表示一個事務有意對數據上共享鎖或者排他鎖。有意表示事務想執行操作但還沒真正執行

鎖的粒度主要分為表鎖和行鎖

表鎖的開銷最小,同時允許的并發量也是最小。MyISAM 存儲引擎使用該鎖機制。當要寫入數據時,整個表記錄被鎖,此時其他讀/寫動作一律等待。一些特定的動作,如 ALTER TABLE 執行時使用的也是表鎖

行鎖可以支持最大的并發,InnoDB 存儲引擎使用該鎖機制。如果要支持并發讀/寫,建議采用 InnoDB 存儲引擎

用 MySQL 實現分布式鎖,你聽過嗎?

以前參加過一個庫存系統,由于其業務復雜性,搞了很多個應用來支撐。這樣的話一份庫存數據就有可能同時有多個應用來修改庫存數據。

比如說,有定時任務域xx.cron,和SystemA域和SystemB域這幾個JAVA應用,可能同時修改同一份庫存數據。如果不做協調的話,就會有臟數據出現。

對于跨JAVA進程的線程協調,可以借助外部環境,例如DB或者Redis。下文介紹一下如何使用DB來實現分布式鎖。

本文設計的分布式鎖的交互方式如下:

在使用synchronized關鍵字的時候,必須指定一個鎖對象。

進程內的線程可以基于obj來實現同步。obj在這里可以理解為一個鎖對象。如果線程要進入synchronized代碼塊里,必須先持有obj對象上的鎖。這種鎖是JAVA里面的內置鎖,創建的過程是線程安全的。那么借助DB,如何保證創建鎖的過程是線程安全的呢?

可以利用DB中的UNIQUE KEY特性,一旦出現了重復的key,由于UNIQUE KEY的唯一性,會拋出異常的。在JAVA里面,是 SQLIntegrityConstraintViolationException 異常。

transaction_id是事務Id,比如說,可以用

來組裝一個transaction_id,表示某倉庫某銷售模式下的某個條碼資源。不同條碼,當然就有不同的transaction_id。如果有兩個應用,拿著相同的transaction_id來創建鎖資源的時候,只能有一個應用創建成功。

在寫操作頻繁的業務系統中,通常會進行分庫,以降低單數據庫寫入的壓力,并提高寫操作的吞吐量。如果使用了分庫,那么業務數據自然也都分配到各個數據庫上了。

在這種水平切分的多數據庫上使用DB分布式鎖,可以自定義一個DataSouce列表。并暴露一個 getConnection(String transactionId) 方法,按照transactionId找到對應的Connection。

實現代碼如下:

首先編寫一個initDataSourceList方法,并利用Spring的PostConstruct注解初始化一個DataSource 列表。相關的DB配置從db.properties讀取。

DataSource使用阿里的DruidDataSource。

接著最重要的一個實現getConnection(String transactionId)方法。實現原理很簡單,獲取transactionId的hashcode,并對DataSource的長度取模即可。

連接池列表設計好后,就可以實現往distributed_lock表插入數據了。

接下來利用DB的 select for update 特性來鎖住線程。當多個線程根據相同的transactionId并發同時操作 select for update 的時候,只有一個線程能成功,其他線程都block住,直到 select for update 成功的線程使用commit操作后,block住的所有線程的其中一個線程才能開始干活。

我們在上面的DistributedLock類中創建一個lock方法。

當線程執行完任務后,必須手動的執行解鎖操作,之前被鎖住的線程才能繼續干活。在我們上面的實現中,其實就是獲取到當時 select for update 成功的線程對應的Connection,并實行commit操作即可。

那么如何獲取到呢?我們可以利用ThreadLocal。首先在DistributedLock類中定義

每次調用lock方法的時候,把Connection放置到ThreadLocal里面。我們修改lock方法。

這樣子,當獲取到Connection后,將其設置到ThreadLocal中,如果lock方法出現異常,則將其從ThreadLocal中移除掉。

有了這幾步后,我們可以來實現解鎖操作了。我們在DistributedLock添加一個unlock方法。

畢竟是利用DB來實現分布式鎖,對DB還是造成一定的壓力。當時考慮使用DB做分布式的一個重要原因是,我們的應用是后端應用,平時流量不大的,反而關鍵的是要保證庫存數據的正確性。對于像前端庫存系統,比如添加購物車占用庫存等操作,最好別使用DB來實現分布式鎖了。

如果想鎖住多份數據該怎么實現?比如說,某個庫存操作,既要修改物理庫存,又要修改虛擬庫存,想鎖住物理庫存的同時,又鎖住虛擬庫存。其實也不是很難,參考lock方法,寫一個multiLock方法,提供多個transactionId的入參,for循環處理就可以了。這個后續有時間再補上。

MySQL從入門到精通(九) MySQL鎖,各種鎖

鎖是計算機協調多個進程或線程并發訪問某一資源的機制,在數據庫中,除傳統的計算資源(CPU、RAM、I/O)爭用外,數據也是一種供許多用戶共享的資源,如何保證數據并發訪問的一致性,有效性是所有數據庫必須解決的一個問題,鎖沖突也是影響數據庫并發訪問性能的一個重要因素,從這個角度來說,鎖對數據庫而言是尤其重要,也更加復雜。MySQL中的鎖,按照鎖的粒度分為:1、全局鎖,就鎖定數據庫中的所有表。2、表級鎖,每次操作鎖住整張表。3、行級鎖,每次操作鎖住對應的行數據。

全局鎖就是對整個數據庫實例加鎖,加鎖后整個實例就處于只讀狀態,后續的DML的寫語句,DDL語句,已經更新操作的事務提交語句都將阻塞。其典型的使用場景就是做全庫的邏輯備份,對所有的表進行鎖定,從而獲取一致性視圖,保證數據的完整性。但是對數據庫加全局鎖是有弊端的,如在主庫上備份,那么在備份期間都不能執行更新,業務會受影響,第二如果是在從庫上備份,那么在備份期間從庫不能執行主庫同步過來的二進制日志,會導致主從延遲。

解決辦法是在innodb引擎中,備份時加上--single-transaction參數來完成不加鎖的一致性數據備份。

添加全局鎖: flush tables with read lock; 解鎖 unlock tables。

表級鎖,每次操作會鎖住整張表.鎖定粒度大,發送鎖沖突的概率最高,并發讀最低,應用在myisam、innodb、BOB等存儲引擎中。表級鎖分為: 表鎖、元數據鎖(meta data lock, MDL)和意向鎖。

表鎖又分為: 表共享讀鎖 read lock、表獨占寫鎖write lock

語法: 1、加鎖 lock tables 表名 ... read/write

2、釋放鎖 unlock tables 或者關閉客戶端連接

注意: 讀鎖不會阻塞其它客戶端的讀,但是會阻塞其它客戶端的寫,寫鎖既會阻塞其它客戶端的讀,又會阻塞其它客戶端的寫。大家可以拿一張表來測試看看。

元數據鎖,在加鎖過程中是系統自動控制的,無需顯示使用,在訪問一張表的時候會自動加上,MDL鎖主要作用是維護表元數據的數據一致性,在表上有活動事務的時候,不可以對元數據進行寫入操作。為了避免DML和DDL沖突,保證讀寫的正確性。

在MySQL5.5中引入了MDL,當對一張表進行增刪改查的時候,加MDL讀鎖(共享);當對表結構進行變更操作時,加MDL寫鎖(排他).

查看元數據鎖:

select object_type,object_schema,object_name,lock_type,lock_duration from performance_schema_metadata_locks;

意向鎖,為了避免DML在執行時,加的行鎖與表鎖的沖突,在innodb中引入了意向鎖,使得表鎖不用檢查每行數據是否加鎖,使用意向鎖來減少表鎖的檢查。意向鎖分為,意向共享鎖is由語句select ... lock in share mode添加。意向排他鎖ix,由insert,update,delete,select。。。for update 添加。

select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from performance_schema.data_lock;

行級鎖,每次操作鎖住對應的行數據,鎖定粒度最小,發生鎖沖突的概率最高,并發讀最高,應用在innodb存儲引擎中。

innodb的數據是基于索引組織的,行鎖是通過對索引上的索引項加鎖來實現的,而不是對記錄加的鎖,對于行級鎖,主要分為以下三類:

1、行鎖或者叫record lock記錄鎖,鎖定單個行記錄的鎖,防止其他事物對次行進行update和delete操作,在RC,RR隔離級別下都支持。

2、間隙鎖Gap lock,鎖定索引記錄間隙(不含該記錄),確保索引記錄間隙不變,防止其他事物在這個間隙進行insert操作,產生幻讀,在RR隔離級別下都支持。

3、臨鍵鎖Next-key-lock,行鎖和間隙鎖組合,同時鎖住數據,并鎖住數據前面的間隙Gap,在RR隔離級別下支持。

innodb實現了以下兩種類型的行鎖

1、共享鎖 S: 允許一個事務去讀一行,阻止其他事務獲得相同數據集的排他鎖。

2、排他鎖 X: 允許獲取排他鎖的事務更新數據,阻止其他事務獲得相同數據集的共享鎖和排他鎖。

insert 語句 排他鎖 自動添加的

update語句 排他鎖 自動添加

delete 語句 排他鎖 自動添加

select 正常查詢語句 不加鎖 。。。

select 。。。lock in share mode 共享鎖 需要手動在select 之后加lock in share mode

select 。。。for update 排他鎖 需要手動在select之后添加for update

默認情況下,innodb在repeatable read事務隔離級別運行,innodb使用next-key鎖進行搜索和索引掃描,以防止幻讀。

間隙鎖唯一目的是防止其它事務插入間隙,間隙鎖可以共存,一個事務采用的間隙鎖不會阻止另一個事務在同一間隙上采用的間隙鎖。

如何基于MySQL的行鎖來實現悲觀鎖?

首先僅僅加上selelct for update是不足夠的,還必須利用事務保證操作的原子性。

保證不會出現多線程并發問題:

僅僅使用事務保證原子性:

其他線程還是可以獲取記錄進行覆蓋。

僅僅使用了行鎖:

MySQL的每一個操作都是開啟事務的,并且會自動提交,僅僅加入行鎖,第一步操作后就事務提交釋放,依舊會被覆蓋記錄。

MySQL數據庫表鎖定的幾種方法實現

如果兩個程序都向表中寫數據顯然會造成很大的麻煩,甚至會有意外情況發生。如果表正由一個程序寫入,同時進行讀取的另一個程序也會產生混亂的結果。

鎖定表的方法

防止客戶機的請求互相干擾或者服務器與維護程序相互干擾的方法主要有多種。如果你關閉數據庫,就可以保證服務器

和myisamchk和isamchk之間沒有交互作用。但是停止服務器的運行并不是一個好注意,因為這樣做會使得沒有故障的數據庫和表也不可用。本節主

要討論的過程,是避免服務器和myisamchk或isamchk之間的交互作用。實現這種功能的方法是對表進行鎖定。

服務器由兩種表的鎖定方法:

1.內部鎖定

內部鎖定可以避免客戶機的請求相互干擾——例如,避免客戶機的SELECT查詢被另一個客戶機的UPDATE查詢所干擾。也可以利用內部鎖定機制防止服務器在利用myisamchk或isamchk檢查或修復表時對表的訪問。

語法:鎖定表:LOCK TABLES tbl_name {READ | WRITE},[ tbl_name {READ | WRITE},…]

解鎖表:UNLOCK TABLES

LOCK TABLES為當前線程鎖定表。UNLOCK TABLES釋放被當前線程持有的任何鎖。當線程發出另外一個LOCK TABLES時,或當服務器的連接被關閉時,當前線程鎖定的所有表自動被解鎖。

如果一個線程獲得在一個表上的一個READ鎖,該線程(和所有其他線程)只能從表中讀。如果一個線程獲得一個表上的一個WRITE鎖,那么只有持鎖的線程READ或WRITE表,其他線程被阻止。

每個線程等待(沒有超時)直到它獲得它請求的所有鎖。

WRITE鎖通常比READ鎖有更高的優先級,以確保更改盡快被處理。這意味著,如果一個線程獲得READ鎖,并且然后另外一個線程請求一個WRITE鎖, 隨后的READ鎖請求將等待直到WRITE線程得到了鎖并且釋放了它。

顯然對于檢查,你只需要獲得讀鎖。再者鐘情跨下,只能讀取表,但不能修改它,因此他也允許其它客戶機讀取表。對于修復,你必須獲得些所以防止任何客戶機在你對表進行操作時修改它。

2.外部鎖定

服務器還可以使用外部鎖定(文件級鎖)來防止其它程序在服務器使用表時修改文件。通常,在表的檢查操作中服務器

將外部鎖定與myisamchk或isamchk作合使用。但是,外部鎖定在某些系統中是禁用的,因為他不能可靠的進行工作。對運行myisamchk或

isamchk所選擇的過程取決于服務器是否能使用外部鎖定。如果不使用,則必修使用內部鎖定協議。

如果服務器用--skip-locking選項運行,則外部鎖定禁用。該選項在某些系統中是缺省的,如Linux。可以通過運行mysqladmin variables命令確定服務器是否能夠使用外部鎖定。檢查skip_locking變量的值并按以下方法進行:◆如果skip_locking為off,則外部鎖定有效您可以繼續并運行人和一個實用程序來檢查表。服務器和實用程序將合作對表進行訪問。但是,運行任何

一個實用程序之前,應該使用mysqladmin flush-tables。為了修復表,應該使用表的修復鎖定協議。

◆如果skip_locaking為on,則禁用外部鎖定,所以在myisamchk或isamchk檢查修復表示服務器并不知道,最好關閉服務器。如果堅

持是服務器保持開啟狀態,月確保在您使用此表示沒有客戶機來訪問它。

深入理解MySQL數據庫各種鎖(總結)

MyISAM和InnoDB存儲引擎使用的鎖:

封鎖粒度小:

由于InnoDB存儲引擎支持的是行級別的鎖,因此意向鎖(因為意向鎖是表鎖)其實不會阻塞除全表掃以外的任何請求。故表級意向鎖與行級鎖的兼容性如下所示

參考

參考

行鎖的三種算法:

這條語句阻止其他事務插入10和20之間的數字,無論這個數字是否存在。 間隙可以跨越0個,單個或多個索引值。

共享鎖:

排他鎖:

樂觀鎖:總是假設最好的情況,每次去拿數據的時候都認為別人不會修改(天真), 操作數據時不會上鎖 ,但是 更新時會判斷在此期間有沒有別的事務更新這個數據,若被更新過,則失敗重試 ;適用于讀多寫少的場景。

樂觀鎖的實現方式 有:

關閉自動提交后,我們需要手動開啟事務。

上述就實現了悲觀鎖,悲觀鎖就是悲觀主義者,它會認為我們在事務A中操作數據1的時候,一定會有事務B來修改數據1,所以,在第2步我們將數據查詢出來后直接加上排它鎖(X)鎖,防止別的事務來修改事務1,直到我們commit后,才釋放了排它鎖。

網站標題:mysql鎖怎么實現,mysql鎖的實現
文章出自:http://m.kartarina.com/article36/hddjsg.html

成都網站建設公司_創新互聯,為您提供靜態網站搜索引擎優化移動網站建設服務器托管微信小程序網站建設

廣告

聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯

小程序開發
主站蜘蛛池模板: 人妻无码人妻有码中文字幕| 精品无码成人片一区二区98 | 国产精品一级毛片无码视频| 亚洲日韩看片无码电影| 亚洲av无码有乱码在线观看| 国产精品成人无码久久久久久| 国产成人A人亚洲精品无码| 无码精品A∨在线观看十八禁| 中文字幕丰满伦子无码 | 国产亚洲?V无码?V男人的天堂 | 人妻aⅴ中文字幕无码| 伊人久久无码中文字幕| 亚洲av永久无码| 亚洲AV无码一区二区乱孑伦AS| 国产精品无码久久av不卡| 蜜桃无码AV一区二区| 国产亚洲精久久久久久无码| 亚洲最大av无码网址| 性虎精品无码AV导航| 精品成在人线AV无码免费看| 亚洲日韩精品A∨片无码| 精品无码久久久久久久久| 50岁人妻丰满熟妇αv无码区| 国产激情无码视频在线播放性色 | 亚洲av日韩av高潮潮喷无码| 亚洲男人在线无码视频| 国产成人无码精品一区不卡| 亚洲国产精品无码久久久| 无套内射在线无码播放| 无码精品A∨在线观看中文| 国产精品无码成人午夜电影| 国产成人无码一二三区视频 | 亚洲ⅴ国产v天堂a无码二区| 国产av无码专区亚洲av果冻传媒 | 亚洲AV中文无码乱人伦在线视色| 亚洲欧洲无码一区二区三区| 中文字幕人成无码人妻综合社区| 亚洲av永久无码精品漫画 | 亚洲av成人中文无码专区| AV大片在线无码永久免费| 久久无码AV一区二区三区|