mysql的鎖--行鎖,表鎖,樂觀鎖,悲觀鎖
一 引言--為什麼mysql提供了鎖
最近看到了mysql有行鎖和表鎖兩個概念,越想越疑惑。為什麼mysql要提供鎖機制,而且這種機制不是一個擺設,還有很多人在用。在現代資料庫裡幾乎有事務機制,acid的機制應該能解決併發排程的問題了,為什麼還要主動加鎖呢?
後來看到一篇文章,“防止更新丟失,並不能單靠資料庫事務控制器來解決,需要應用程式對要更新的資料加必要的鎖來解決”。瞬間,世界觀都崩塌了。非常不敢相信,於是自己寫了程式碼檢驗一下。
資料庫表是這樣的。用count欄位來做100次累加。
為了保證實驗的科學性,先確認了資料庫是InnoDB的(查看錶使用的儲存引擎:show table status from db_name where name='table_name';
定義一個任務,讀count值--> 程式count++-->寫資料庫
publicclass LostUpdate implements Runnable{
privateCountDownLatch countDown;
public LostUpdate(CountDownLatch countDown){
this.countDown = countDown;
}
@Override
publicvoid run() {
Connection conn=null
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8",
"root", "123");
} catch (Exception e) {
e.printStackTrace();
return;
}
try {
conn.setAutoCommit
//不加鎖的情況
PreparedStatement ps =conn.prepareStatement("select * from LostUpdate where id =1");
//加鎖的情況
//PreparedStatement ps =conn.prepareStatement("select * from LostUpdate where id =1 for update");
ResultSet rs=ps.executeQuery();
int count = 0;
while(rs.next()){
count= rs.getInt("count");
}
count++;
ps =conn.prepareStatement("update LostUpdate set count=? where id =1");
ps.setInt(1, count);
ps.executeUpdate();
conn.commit();
} catch (Exception e) {
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
//表示一次任務完成 countDown.countDown();
}
}
主執行緒下建立子執行緒,模擬多執行緒環境
publicclass TestLock {
publicstaticvoid main(String[] args) throws InterruptedException {
//建立執行緒池,裡面有10個執行緒,共執行100次+1操作
finalint THREAD_COUNT=10;
finalint RUN_TIME=100;
ExecutorService threadPool=Executors.newFixedThreadPool(THREAD_COUNT);
//用CountDownLatch保證主執行緒等待所有任務完成
CountDownLatch count=newCountDownLatch(RUN_TIME);
for(int i=0;i<RUN_TIME;i++)
threadPool.execute(new LostUpdate(count));
threadPool.shutdown();
count.await();
//提示所有任務執行完
System.out.println("finish");
}
}
執行結果是:
大概解釋一下程式,就是建立了一個執行緒池,裡面10個執行緒,執行100次任務。每個任務就是 讀count值--程式count++--寫資料庫,經典的銀行存款(丟失修改)問題。事實勝於雄辯,結論就是上面的橙色字,解決丟失修改不能靠事務,要加必要的鎖,所以資料庫提供的鎖不是個擺設。
二 資料庫事務機制
為了找到問題的根源,為了拯救我崩潰的世界觀,我又去回顧了資料庫事務的知識。借鑑這篇
資料庫的acid屬性
· 原性性(Actomicity):事務是一個原子操作單元,其對資料的修改,要麼全都執行,要麼全都不執行。
· 一致性(Consistent):在事務開始和完成時,資料都必須保持一致狀態。這意味著所有相關的資料規則都必須應用於事務的修改,以保持完整性;事務結束時,所有的內部資料結構(如B樹索引或雙向連結串列)也都必須是正確的。
· 隔離性(Isolation):資料庫系統提供一定的隔離機制,保證事務在不受外部併發操作影響的“獨立”環境執行。這意味著事務處理過程中的中間狀態對外部是不可見的,反之亦然。
· 永續性(Durable):事務完成之後,它對於資料的修改是永久性的,即使出現系統故障也能夠保持。
說好的一致性呢,童話裡都是騙人的!!
事務併發排程的問題
1. 髒讀(dirty read):A事務讀取B事務尚未提交的更改資料,並在這個資料基礎上操作。如果B事務回滾,那麼A事務讀到的資料根本不是合法的,稱為髒讀。在oracle中,由於有version控制,不會出現髒讀。
2. 不可重複讀(unrepeatable read):A事務讀取了B事務已經提交的更改(或刪除)資料。比如A事務第一次讀取資料,然後B事務更改該資料並提交,A事務再次讀取資料,兩次讀取的資料不一樣。
3. 幻讀(phantom read):A事務讀取了B事務已經提交的新增資料。注意和不可重複讀的區別,這裡是新增,不可重複讀是更改(或刪除)。這兩種情況對策是不一樣的,對於不可重複讀,只需要採取行級鎖防止該記錄資料被更改或刪除,然而對於幻讀必須加表級鎖(個人認為也可能是GAP鎖),防止在這個表中新增一條資料。
4. 第一類丟失更新(update):A事務撤銷時,把已提交的B事務的資料覆蓋掉。
5. 第二類丟失更新(add/delete):A事務提交時,把已提交的B事務的資料覆蓋掉。
三級封鎖協議
1. 一級封鎖協議:事務T中如果對資料R有寫操作,必須在這個事務中對R的第一次讀操作前對它加X鎖,直到事務結束才釋放。事務結束包括正常結束(COMMIT)和非正常結束(ROLLBACK)。
2. 二級封鎖協議:一級封鎖協議加上事務T在讀取資料R之前必須先對其加S鎖,讀完後方可釋放S鎖。
3. 三級封鎖協議 :一級封鎖協議加上事務T在讀取資料R之前必須先對其加S鎖,直到事務結束才釋放。
可見,三級鎖操作一個比一個厲害(滿足高階鎖則一定滿足低階鎖)。但有個非常致命的地方,一級鎖協議就要在第一次讀加x鎖,直到事務結束。幾乎就要在整個事務加寫鎖了,效率非常低。三級封鎖協議只是一個理論上的東西,實際資料庫常用另一套方法來解決事務併發問題。
隔離性級別
mysql用意向鎖(另一種機制)來解決事務併發問題,為了區別封鎖協議,弄了一個新概念隔離性級別:包括Read Uncommitted、Read Committed、Repeatable Read、Serializable,見這篇。mysql 一般預設Repeatable Read。
終於發現自己為什麼會誤會事務能解決丟失修改了。至於為什麼隔離性級別不解決丟失修改,我猜是有更好的解決方案吧。
總結一下,repeatable read能解決髒讀和不可重複讀,但不嗯呢該解決丟失修改。
三 mysql的行鎖和表鎖
說了那麼久,終於入正題了,先來說說什麼是行鎖和表鎖。
· 表級鎖:每次操作鎖住整張表。開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖衝突的概率最高,併發度最低;
· 行級鎖:每次操作鎖住一行資料。開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的概率最低,併發度也最高;
· 頁面鎖:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,併發度一般。
1 MyISAM的鎖
稍微提一下MyISAM,只說和InnoDB不同的。
a. MyISAM只有表鎖,鎖又分為讀鎖和寫鎖。
b. 沒有事務(不支援事務更準確),不用考慮併發問題,世界和平~
c. 由於鎖的粒度太大,所以當該表寫併發量較高時,要等待的查詢就會很多了。優化見這裡。
2 InnoDB的行鎖和表鎖
沒有特定的語法。mysql的行鎖是通過索引體現的,參考。
如果where條件中只用到索引項,則加的是行鎖;否則加的是表鎖。比如說主鍵索引,唯一索引和聚簇索引等。如果sql的where是全表掃描的,想加行鎖也愛莫能助。
行鎖和表鎖對我們程式設計有什麼影響,要在where中儘量只用索引項,否則就會觸發表鎖。另一個可能是,我們發瘋了地想優化查詢,但where子句中就是有非索引項,於是我們自己寫連線?
行鎖和表鎖各適合怎麼樣的應用,待求證?。(個人認為行鎖適合寫多讀少,表鎖適合讀多寫少。)
3 讀鎖和寫鎖
InnoDB用意向鎖?實現隔離性級別,原理未名,貼張圖:
回想鎖協議,對什麼操作加什麼鎖是一個問題,加鎖加到什麼時候又是一個問題。鎖協議裡常常會看到“加鎖直到事務結束”的煩心字樣。而在InnoDB中,select,insert,update,delete等語句執行時都會自動加解鎖。select的鎖一般執行完就釋放了,修改操作的X鎖會持有到事務結束,效率高很多。至於詳細的加鎖原理,見這裡,搜“InnoDB儲存引擎中不同SQL在不同隔離級別下鎖比較”
mysql也給使用者提供了加鎖的機會,只要在sql後加LOCK IN SHARE MODE 或FOR UPDATE
共享鎖(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE排他鎖(X):SELECT * FROM table_name WHERE ... FOR UPDATE
值得注意的是,自己加的鎖沒有釋放鎖的語句,所以鎖會持有到事務結束。
mysql 還提供了LOCK TABLES,UNLOCK TABLES,用於加表鎖,怎麼用還不太清楚?
4 考察加鎖的情況
加了讀鎖還是寫鎖,加了行鎖還是表鎖,說什麼時候釋放,可以從原理上分析。但剛開始時我不太懂原理,於是又寫了個程式。
publicclass ForUpdate1 implements Runnable{
privateCountDownLatch countDown;
public ForUpdate1(CountDownLatch countDown){
this.countDown = countDown;
}
@Override
publicvoid run() {
Connection conn=null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8",
"root", "123");
} catch (Exception e) {
e.printStackTrace();
return;
}
try {
conn.setAutoCommit(false);
/*PreparedStatement ps =conn.prepareStatement("select * from LostUpdate where id =1 for update");
ps.executeQuery();*/
PreparedStatement ps =conn.prepareStatement("update LostUpdate set count =1 where id =1");
ps.executeUpdate();
Thread.sleep(10000);
conn.commit();
System.out.println("test 1 finish");
countDown.countDown();
} catch (Exception e) {
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
}
}
publicclass ForUpdate2 implements Runnable{
private CountDownLatch countDown;
public ForUpdate2(CountDownLatch countDown){
this.countDown = countDown;
}
@Override
publicvoid run() {
Connection conn=null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8",
"root", "123");
} catch (Exception e) {
e.printStackTrace();
return;
}
try {
Thread.sleep(2000);
conn.setAutoCommit(false);
PreparedStatement ps =conn.prepareStatement("select * from LostUpdate where id =1 for update");
ps.executeQuery();
/*PreparedStatement ps =conn.prepareStatement("update LostUpdate set count =1 where id =1");
ps.executeUpdate();*/
conn.commit();
System.out.println("test 2 finish");
countDown.countDown();
} catch (Exception e) {
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
}
}
publicclass TestForUpdate {
publicstaticvoid main(String[] args) throws InterruptedException {
finalintTHREAD_COUNT=10;(兩個執行緒)
ExecutorService threadPool=Executors.newFixedThreadPool(THREAD_COUNT);
CountDownLatch count=new CountDownLatch(2);(這裡覺得了是兩個執行緒)
//兩次提交
threadPool.execute(new ForUpdate1(count));
threadPool.execute(new ForUpdate2(count));
threadPool.shutdown();
count.await();
mman tro 建立 pro lena ont mysq 提示 sql數據庫 MySQL命令行導出導入數據庫,數據庫備份還原
MySQL命令行導出數據庫:1,進入MySQL目錄下的bin文件夾:cd MySQL中到bin文件夾的目錄如我輸入的命令行:cd C:\Pro
由於業務的需要,需要從兩個資料庫中取得資料,伺服器A儲存有角色使用者配置表和角色表,伺服器B有使用者表和公司表。先不管架構為什麼要這樣設計資料表,因為確實有這樣的需求,但是這確實是一個令人頭疼的事情,但是還是要面帶微笑~
解決思路一:
在資料庫中聯合不同資料庫的表中的DDL
1、建立資料庫
create database python charset=utf8;
2、使用資料庫
use python;
3、建立表結構
create table student(
id int primary key auto_increment
由於專案需要,需要一次性建5000張表,且每張表的命名為Target0001-Target5000:程式碼如下:/*下面迴圈建立有誤,第一行 '4' 附近有錯誤*/
declare @ii int
DECLARE @length INT
set @ii = 1
SET @l
在電腦科學中,鎖是在執行多執行緒時用於強行限制資源訪問的同步機制,即用於在併發控制中保證對互斥要求的滿足。
在DBMS中,可以按照鎖的粒度把資料庫鎖分為行級鎖(INNODB引擎)、表級鎖(MYISAM引擎)和頁級鎖(BDB引擎 )。
行級鎖
行級鎖是Mysql中鎖定粒度最細的一種
MySQL/InnoDB的加鎖,一直是一個面試中常問的話題。例如,資料庫如果有高併發請求,如何保證資料完整性?產生死鎖問題如何排查並解決?我在工作過程中,也會經常用到,樂觀鎖,排它鎖,等。於是今天就對這幾個概念進行學習,屢屢思路,記錄一下。
注:MySQL是一
MySQL是一個支援外掛式儲存引擎的資料庫系統。本文下面的所有介紹,都是基於InnoDB儲存引擎,其他引擎的表現,會有較大的區別。
儲存引擎檢視
MySQL給開發者提供了查詢儲存引擎的功能,我這裡使用的是MySQL5.5.28,可以使用:
show engine
一 引言--為什麼mysql提供了鎖 最近看到了mysql有行鎖和表鎖兩個概念,越想越疑惑。為什麼mysql要提供鎖機制,而且這種機制不是一個擺設,還有很多人在用。在現代資料庫裡幾乎有事務機制,acid的機制應該能解決併發排程的問題了,為什麼還要主動加鎖呢? 後來看到一篇 開始 mode 由於 一個數 table 並且 增刪改 又能 對數 鎖主要用於多用戶環境下保證數據庫完整性和一致性。 我們知道,多個用戶能夠同時操縱同一個數據庫中的數據,會發生數據不一致現象。即如果沒有鎖定且多個用戶同時訪問一個數據庫,則當他們的事務同時使用相同
悲觀鎖:
顧名思義,很悲觀,就是每次拿資料的時候都認為別的執行緒會修改資料,所以在每次拿的時候都會給資料上鎖。上鎖之後,當別的執行緒想要拿資料時,就會阻塞,直到給資料上鎖的執行緒將事務提交或者回滾。傳統的關係型資料庫裡就用到了很多這種鎖機制,比如行鎖,表鎖,共享鎖,排他鎖等,都是在做操作之前 在說具體的鎖結構時,先思考一個問題,那就是為什麼要上鎖?然後我要如何選擇鎖?鎖具體如何實現?
在文章得末尾我給出了我的個人答案。
一、什麼是悲觀鎖?
1、悲觀鎖就是在操作資料時,認為此操作會出現資料衝突,所以在進行每次操作時都要通過獲取鎖才能進行對相同資料的操作,這點跟java中的synchronized
樂觀鎖、悲觀鎖:http://blog.csdn.net/hongchangfirst/article/details/26004335
行鎖、表鎖:http://blog.sina.com.cn/s/blog_703074da0101ghsh.html
ans 唯一索引 crazy cimage -h insert tran 存在 gin
Mysql加鎖過程詳解(1)-基本知識
Mysql加鎖過程詳解(2)-關於mysql 幻讀理解
Mysql加鎖過程詳解(3)-關於mysql 幻讀理解
Mysql加鎖過程詳解(4)- 數據庫操作 重要 讀寫 收購 線程並發 串行化 之前 並發執行 引擎 回顧:
ACID:DBMS在寫入或更新資料的過程中,為保證事務正確可靠,具有的四個特性:原子性(不可分割性)、一致性、隔離性(獨立性)、持久性
一個事務:一系列數據庫操作組成的一個完整的邏輯過程
原子性: 搜索 ash 能力 缺點 外部 加鎖 結構 create 主從 一、 兩種存儲引擎:MyISAM與InnoDB 區別與作用
1. count運算上的區別:
因為MyISAM緩存有表meta-data(行數等),因此在做COUNT(*)時對於一個結構很好的查詢是不需要消耗多少
實驗環境:
mysql5.6
儲存引擎:innoDB
我們在操作資料庫的時候,可能會由於併發問題而引起的資料的不一致性(資料衝突)
樂觀鎖
樂觀鎖不是資料庫自帶的,需要我們自己去實現。樂觀鎖是指操作資料庫時(更新操作),想法很樂觀,認為這次的操作不會導致衝突,在
樂觀鎖
樂觀鎖是指在操作資料庫時(更新操作),想法很樂觀,認為此次操作不會導致衝突,所以在操作資料時,不進行任何其他的特殊處理(也就是不加鎖),而在進行更新後,再去判斷是否有衝突。
悲觀鎖
悲觀鎖是指在操作資料庫時(更新操作),想法很悲觀,認為此次操作會出現衝突,所以在
原文地址:http://blog.csdn.net/mysteryhaohao/article/details/51669741
鎖,在現實生活中是為我們想要隱藏於外界所使用的一種工具。在計算機中,是協調多個程序或執行緒併發訪問某一資源的一種機制。在資料庫當中,除了傳統
鎖是計算機協調多個程序或執行緒併發訪問某一資源的機制。在資料庫中,除傳統的計算資源(如CPU、RAM、I/O等)的爭用以外,資料也是一種供許多使用者共享的資源。如何保證資料併發訪問的一致性、有效性是所有資料庫必須解決的一個問題,鎖衝突也是影響資料庫併發訪問效能的一個重要因素。從這個角度來說,鎖對資料
1.高併發的時候有2種處理
1)後端進行執行緒安全處理,synchrnoized,還有其他不同粒度的鎖
2)在資料庫設定鎖,當你讀的時候,不允許其他人修改。可以用mysql的悲觀鎖
2.悲觀鎖
select * from 表名 for update
for update很重 相關推薦
第二百九十節,MySQL數據庫-MySQL命令行導出導入數據庫,數據庫備份還原
java Mysql的跨伺服器不同表結構的聯合查詢,兩不同伺服器上的不同表查詢
20181022mysql操作一:建立庫,表的增刪改查,資料的增刪改
Sql批量建表、刪表,表名以數字命名,且固定長度
MySQL中的行級鎖,表級鎖,頁級鎖
MySQL/InnoDB中,樂觀鎖、悲觀鎖、共享鎖、排它鎖、行鎖、表鎖、死鎖概念的理解
mysql/innoDB中,樂觀鎖,悲觀鎖,共享鎖,排他鎖,行鎖,表鎖,死鎖概念的理解
mysql的鎖--行鎖,表鎖,樂觀鎖,悲觀鎖
數據庫行鎖,表鎖
悲觀鎖,樂觀鎖,行鎖,表鎖,頁鎖,共享鎖,排他鎖
悲觀鎖,樂觀鎖,排他鎖,行鎖----MYSQL
資料庫中的行鎖、表鎖,樂觀鎖悲觀鎖
Mysql加鎖過程詳解(9)-innodb下的記錄鎖,間隙鎖,next-key鎖
MySQL-----鎖(行鎖、表鎖、頁鎖、樂觀鎖、悲觀鎖)
Mysql MyISAM與InnoDB 表鎖行鎖以及分庫分表優化
對mysql樂觀鎖、悲觀鎖、共享鎖、排它鎖、行鎖、表鎖概念的理解
MySQL中樂觀鎖、悲觀鎖、共享鎖、排它鎖、行鎖、表鎖的概念
MySQL中鎖詳解(行鎖、表鎖、頁鎖、悲觀鎖、樂觀鎖等)
MySQL表鎖行鎖詳解MyISAM與Innodb比較
mysql悲觀鎖,高併發