2020重新出發(fā)备蚓,MySql基礎(chǔ),MySql事務(wù)

@[toc]

MySQL事務(wù)和字符集

當(dāng)多個(gè)用戶訪問同一數(shù)據(jù)時(shí)囱稽,一個(gè)用戶在更改數(shù)據(jù)的過程中可能有其它用戶同時(shí)發(fā)起更改請求郊尝,為保證數(shù)據(jù)的一致性狀態(tài),MySQL 引入了事務(wù)战惊。

MySQL事務(wù)的作用

在銀行業(yè)務(wù)中流昏,有一條記賬原則,即有借有貸,借貸相等横缔。為了保證這種原則,每發(fā)生一筆銀行業(yè)務(wù)衫哥,就必須確保會(huì)計(jì)賬目上借方科目和貸方科目至少各記一筆茎刚,并且這兩筆賬要么同時(shí)成功,要么同時(shí)失敗撤逢。如果出現(xiàn)只記錄了借方科目膛锭,或者只記錄了貸方科目的情況,就違反了記賬原則蚊荣。會(huì)出現(xiàn)記錯(cuò)賬的情況初狰。

在銀行的日常業(yè)務(wù)中,只要是同一銀行(如都是中國農(nóng)業(yè)銀行互例,簡稱農(nóng)行)奢入,一般都支持賬戶間的直接轉(zhuǎn)賬。因此媳叨,銀行轉(zhuǎn)賬操作往往會(huì)涉及兩個(gè)或兩個(gè)以上的賬戶腥光。在轉(zhuǎn)出賬戶的存款減少一定金額的同時(shí),轉(zhuǎn)入賬戶的存款就要增加相應(yīng)的金額糊秆。

下面武福,在 MySQL 數(shù)據(jù)庫中模擬一下上述提及的轉(zhuǎn)賬問題。

假如要從張三的賬戶直接轉(zhuǎn)賬 500 元到李四的賬戶痘番。首先需要?jiǎng)?chuàng)建賬戶表捉片,存放用戶張三和李四的賬戶信息。創(chuàng)建賬戶表和插入數(shù)據(jù)的 SQL 語句和運(yùn)行結(jié)果如下所示:

mysql> CREATE DATABASE mybank;
Query OK, 1 row affected (0.02 sec)
mysql> USE mybank;
Database changed
mysql> CREATE TABLE bank(
    -> customerName VARCHAR(20),   #用戶名
    -> currentMoney DECIMAL(10,2)    #當(dāng)前余額
    -> )ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.26 sec)

mysql> INSERT INTO bank (customerName,currentMoney) VALUES('張三',1000);;
Query OK, 1 row affected (0.07 sec)

mysql> INSERT INTO bank (customerName,currentMoney) VALUES('李四',1);
Query OK, 1 row affected (0.08 sec)

查詢 bank 數(shù)據(jù)表的 SQL 語句和運(yùn)行結(jié)果如下:

mysql> SELECT * FROM bank;
+--------------+--------------+
| customerName | currentMoney |
+--------------+--------------+
| 張三         |      1000.00 |
| 李四         |         1.00 |
+--------------+--------------+
2 rows in set (0.02 sec)

結(jié)果顯示汞舱,張三和李四兩個(gè)賬戶的余額總和為 1000+1=1001 元伍纫。

下面開始模擬實(shí)現(xiàn)轉(zhuǎn)賬功能。從張三的賬戶直接轉(zhuǎn)賬 500 元到李四的賬戶昂芜,可以使用 UPDATE 語句分別修改張三的賬戶和李四的賬戶翻斟。張三的賬戶減少 500 元,李四的賬戶增加 500 元说铃, SQL 語句如下所示:

/*轉(zhuǎn)賬測試:張三轉(zhuǎn)賬給李四 500 元*/
#張三的賬戶少 500 元访惜,李四的賬戶多 500 元
UPDATE bank SET currentMoney = currentMoney-500 WHERE customerName = '張三';
UPDATE bank SET currentMoney = currentMoney+500 WHERE customerName = '李四';

正常情況下,執(zhí)行以上的轉(zhuǎn)賬操作后腻扇,余額總和應(yīng)保持不變债热,仍為 1001 元。但是幼苛,如果在這個(gè)過程的其中一個(gè)環(huán)節(jié)出現(xiàn)差錯(cuò)窒篱,如在張三的賬戶減少 500 元之后,這時(shí)發(fā)生了服務(wù)器故障,李四的賬戶沒有立即增加 500 元墙杯,此時(shí)配并,第三方讀取到兩個(gè)賬戶的余額總和變?yōu)?500+1=501 元,即賬戶總額間少了 500 元高镐。

MySQL 為了解決此類問題溉旋,提供了事務(wù)。事務(wù)可以將一系列的數(shù)據(jù)操作捆綁成一個(gè)整體進(jìn)行統(tǒng)一管理嫉髓,如果某一事務(wù)執(zhí)行成功观腊,則在該事務(wù)中進(jìn)行的所有數(shù)據(jù)更改均會(huì)提交,成為數(shù)據(jù)庫中的永久組成部分算行。如果事務(wù)執(zhí)行時(shí)遇到錯(cuò)誤梧油,則就必須取消或回滾。取消或回滾后州邢,數(shù)據(jù)將全部恢復(fù)到操作前的狀態(tài)儡陨,所有數(shù)據(jù)的更改均被清除。

MySQL 通過事務(wù)保證了數(shù)據(jù)的一致性量淌。上述提到的轉(zhuǎn)賬過程就是一個(gè)事務(wù)迄委,它需要兩條 UPDATE 語句來完成。這兩條語句是一個(gè)整體类少,如果其中任何一個(gè)環(huán)節(jié)出現(xiàn)問題叙身,則整個(gè)轉(zhuǎn)賬業(yè)務(wù)也應(yīng)取消,兩個(gè)賬戶中的余額應(yīng)恢復(fù)為原來的數(shù)據(jù)硫狞,從而確保轉(zhuǎn)賬前和轉(zhuǎn)賬后的余額總和不變信轿,即都是 1001 元。

事務(wù)的概念和特性

數(shù)據(jù)庫的事務(wù)(Transaction)是一種機(jī)制残吩、一個(gè)操作序列财忽,包含了一組數(shù)據(jù)庫操作命令。事務(wù)把所有的命令作為一個(gè)整體一起向系統(tǒng)提交或撤銷操作請求泣侮,即這一組數(shù)據(jù)庫命令要么都執(zhí)行即彪,要么都不執(zhí)行,因此事務(wù)是一個(gè)不可分割的工作邏輯單元活尊。

在數(shù)據(jù)庫系統(tǒng)上執(zhí)行并發(fā)操作時(shí)隶校,事務(wù)是作為最小的控制單元來使用的,特別適用于多用戶同時(shí)操作的數(shù)據(jù)庫系統(tǒng)蛹锰。例如深胳,航空公司的訂票系統(tǒng)、銀行铜犬、保險(xiǎn)公司以及證券交易系統(tǒng)等舞终。

事務(wù)具有 4 個(gè)特性轻庆,即原子性(Atomicity)、一致性(Consistency)敛劝、隔離性(Isolation)和持久性(Durability)余爆,這 4 個(gè)特性通常簡稱為 ACID。

原子性

事務(wù)是一個(gè)完整的操作夸盟。事務(wù)的各元素是不可分的(原子的)蛾方。事務(wù)中所有元素必須作為一個(gè)整體提交或回滾。如果事務(wù)中的任何元素失敗满俗,則整個(gè)事務(wù)將失敗转捕。

  • 以銀行轉(zhuǎn)賬事務(wù)為例作岖,如果該事務(wù)提交了唆垃,則這兩個(gè)賬戶的數(shù)據(jù)將會(huì)更新。如果由于某種原因痘儡,事務(wù)在成功更新這兩個(gè)賬戶之前終止了辕万,則不會(huì)更新這兩個(gè)賬戶的余額,并且會(huì)撤銷對任何賬戶余額的修改沉删,事務(wù)不能部分提交渐尿。

一致性

當(dāng)事務(wù)完成時(shí),數(shù)據(jù)必須處于一致狀態(tài)矾瑰。也就是說砖茸,在事務(wù)開始之前,數(shù)據(jù)庫中存儲(chǔ)的數(shù)據(jù)處于一致狀態(tài)殴穴。在正在進(jìn)行的事務(wù)中. 數(shù)據(jù)可能處于不一致的狀態(tài)凉夯,如數(shù)據(jù)可能有部分被修改。然而采幌,當(dāng)事務(wù)成功完成時(shí)劲够,數(shù)據(jù)必須再次回到已知的一致狀態(tài)。通過事務(wù)對數(shù)據(jù)所做的修改不能損壞數(shù)據(jù)休傍,或者說事務(wù)不能使數(shù)據(jù)存儲(chǔ)處于不穩(wěn)定的狀態(tài)征绎。

  • 以銀行轉(zhuǎn)賬事務(wù)事務(wù)為例。在事務(wù)開始之前磨取,所有賬戶余額的總額處于一致狀態(tài)人柿。在事務(wù)進(jìn)行的過程中,一個(gè)賬戶余額減少了忙厌,而另一個(gè)賬戶余額尚未修改顷扩。因此,所有賬戶余額的總額處于不一致狀態(tài)慰毅。事務(wù)完成以后隘截,賬戶余額的總額再次恢復(fù)到一致狀態(tài)。

隔離性

對數(shù)據(jù)進(jìn)行修改的所有并發(fā)事務(wù)是彼此隔離的,這表明事務(wù)必須是獨(dú)立的婶芭,它不應(yīng)以任何方式依賴于或影響其他事務(wù)东臀。修改數(shù)據(jù)的事務(wù)可以在另一個(gè)使用相同數(shù)據(jù)的事務(wù)開始之前訪問這些數(shù)據(jù),或者在另一個(gè)使用相同數(shù)據(jù)的事務(wù)結(jié)束之后訪問這些數(shù)據(jù)犀农。

另外惰赋,當(dāng)事務(wù)修改數(shù)據(jù)時(shí)呵恢,如果任何其他進(jìn)程正在同時(shí)使用相同的數(shù)據(jù)禽最,則直到該事務(wù)成功提交之后,對數(shù)據(jù)的修改才能生效净宵。張三和李四之間的轉(zhuǎn)賬與王五和趙二之間的轉(zhuǎn)賬孟害,永遠(yuǎn)是相互獨(dú)立的拒炎。

持久性

事務(wù)的持久性指不管系統(tǒng)是否發(fā)生了故障,事務(wù)處理的結(jié)果都是永久的挨务。

一個(gè)事務(wù)成功完成之后击你,它對數(shù)據(jù)庫所作的改變是永久性的,即使系統(tǒng)出現(xiàn)故障也是如此谎柄。也就是說丁侄,一旦事務(wù)被提交,事務(wù)對數(shù)據(jù)所做的任何變動(dòng)都會(huì)被永久地保留在數(shù)據(jù)庫中朝巫。

事務(wù)的 ACID 原則保證了一個(gè)事務(wù)或者成功提交鸿摇,或者失敗回滾,二者必居其一劈猿。因此拙吉,它對事務(wù)的修改具有可恢復(fù)性。即當(dāng)事務(wù)失敗時(shí)糙臼,它對數(shù)據(jù)的修改都會(huì)恢復(fù)到該事務(wù)執(zhí)行前的狀態(tài)庐镐。

MySQL事務(wù)的語法和流程

MySQL 提供了多種存儲(chǔ)引擎來支持事務(wù)。支持事務(wù)的存儲(chǔ)引擎有 InnoDB 和 BDB变逃,其中必逆,InnoDB 存儲(chǔ)引擎事務(wù)主要通過 UNDO 日志和 REDO 日志實(shí)現(xiàn),MyISAM 存儲(chǔ)引擎不支持事務(wù)揽乱。

拓展:任何一種數(shù)據(jù)庫名眉,都會(huì)擁有各種各樣的日志,用來記錄數(shù)據(jù)庫的運(yùn)行情況凰棉、日常操作损拢、錯(cuò)誤信息等,MySQL 也不例外撒犀。

  • 例如福压,當(dāng)用戶 root 登錄到 MySQL 服務(wù)器掏秩,就會(huì)在日志文件里記錄該用戶的登錄時(shí)間、執(zhí)行操作等荆姆。

為了維護(hù) MySQL 服務(wù)器蒙幻,經(jīng)常需要在 MySQL 數(shù)據(jù)庫中進(jìn)行日志操作:

  • UNDO 日志:復(fù)制事務(wù)執(zhí)行前的數(shù)據(jù),用于在事務(wù)發(fā)生異常時(shí)回滾數(shù)據(jù)胆筒。
  • REDO 日志:記錄在事務(wù)執(zhí)行中邮破,每條對數(shù)據(jù)進(jìn)行更新的操作,當(dāng)事務(wù)提交時(shí)仆救,該內(nèi)容將被刷新到磁盤抒和。

默認(rèn)設(shè)置下,每條 SQL 語句就是一個(gè)事務(wù)彤蔽,即執(zhí)行 SQL 語句后自動(dòng)提交摧莽。為了達(dá)到將幾個(gè)操作做為一個(gè)整體的目的,需要使用 BEGIN 或 START TRANSACTION 開啟一個(gè)事務(wù)铆惑,或者禁止當(dāng)前會(huì)話的自動(dòng)提交范嘱。

執(zhí)行事務(wù)的語法和流程

SQL 使用下列語句來管理事務(wù)送膳。

開始事務(wù)

BEGIN;

START TRANSACTION;

這個(gè)語句顯式地標(biāo)記一個(gè)事務(wù)的起始點(diǎn)员魏。

提交事務(wù)

MySQL 使用下面的語句來提交事務(wù):

COMMIT;

COMMIT 表示提交事務(wù),即提交事務(wù)的所有操作叠聋,具體地說撕阎,就是將事務(wù)中所有對數(shù)據(jù)庫的更新都寫到磁盤上的物理數(shù)據(jù)庫中,事務(wù)正常結(jié)束碌补。

提交事務(wù)虏束,意味著將事務(wù)開始以來所執(zhí)行的所有數(shù)據(jù)都修改成為數(shù)據(jù)庫的永久部分,因此也標(biāo)志著一個(gè)事務(wù)的結(jié)束厦章。一旦執(zhí)行了該命令镇匀,將不能回滾事務(wù)。只有在所有修改都準(zhǔn)備好提交給數(shù)據(jù)庫時(shí)袜啃,才執(zhí)行這一操作汗侵。

回滾(撤銷)事務(wù)

MySQL 使用以下語句回滾事務(wù):

ROLLBACK;

ROLLBACK 表示撤銷事務(wù),即在事務(wù)運(yùn)行的過程中發(fā)生了某種故障群发,事務(wù)不能繼續(xù)執(zhí)行晰韵,系統(tǒng)將事務(wù)中對數(shù)據(jù)庫的所有已完成的操作全部撤銷,回滾到事務(wù)開始時(shí)的狀態(tài)熟妓。這里的操作指對數(shù)據(jù)庫的更新操作雪猪。

當(dāng)事務(wù)執(zhí)行過程中遇到錯(cuò)誤時(shí),使用 ROLLBACK 語句使事務(wù)回滾到起點(diǎn)或指定的保持點(diǎn)處起愈。同時(shí)只恨,系統(tǒng)將清除自事務(wù)起點(diǎn)或到某個(gè)保存點(diǎn)所做的所有的數(shù)據(jù)修改译仗,并且釋放由事務(wù)控制的資源。因此官觅,這條語句也標(biāo)志著事務(wù)的結(jié)束古劲。

總結(jié)

BEGIN 或 START TRANSACTION 語句后面的 SQL 語句對數(shù)據(jù)庫數(shù)據(jù)的更新操作都將記錄在事務(wù)日志中,直至遇到 ROLLBACK 語句或 COMMIT 語句缰猴。如果事務(wù)中某一操作失敗且執(zhí)行了 ROLLBACK 語句产艾,那么在開啟事務(wù)語句之后所有更新的數(shù)據(jù)都能回滾到事務(wù)開始前的狀態(tài)。如果事務(wù)中的所有操作都全部正確完成滑绒,并且使用了 COMMIT 語句向數(shù)據(jù)庫提交更新數(shù)據(jù)闷堡,則此時(shí)的數(shù)據(jù)又處在新的一致狀態(tài)。

在數(shù)據(jù)庫操作中疑故,為了有效保證并發(fā)讀取數(shù)據(jù)的正確性杠览,提出了事務(wù)的隔離級別。在 MySQL 中纵势,事務(wù)的默認(rèn)隔離級別是 REPEATABLE-READ (可重讀)隔離級別踱阿,即事務(wù)未結(jié)束時(shí)(未執(zhí)行 COMMIT 或 ROLLBACK),其它會(huì)話只能讀取到未提交數(shù)據(jù)钦铁。

注意事項(xiàng)

MySQL 事務(wù)是一項(xiàng)非常消耗資源的功能软舌,大家在使用過程中要注意以下幾點(diǎn)。

  1. 事務(wù)盡可能簡短:事務(wù)的開啟到結(jié)束會(huì)在數(shù)據(jù)庫管理系統(tǒng)中保留大量資源牛曹,以保證事務(wù)的原子性佛点、一致性、隔離性和持久性黎比。如果在多用戶系統(tǒng)中超营,較大的事務(wù)將會(huì)占用系統(tǒng)的大量資源,使得系統(tǒng)不堪重負(fù)阅虫,會(huì)影響軟件的運(yùn)行性能演闭,甚至導(dǎo)致系統(tǒng)崩潰。
  2. 事務(wù)中訪問的數(shù)據(jù)量盡量最少:當(dāng)并發(fā)執(zhí)行事務(wù)處理時(shí)颓帝,事務(wù)操作的數(shù)據(jù)量越少米碰,事務(wù)之間對相同數(shù)據(jù)的操作就越少。
  3. 查詢數(shù)據(jù)時(shí)盡量不要使用事務(wù):對數(shù)據(jù)進(jìn)行瀏覽查詢操作并不會(huì)更新數(shù)據(jù)庫的數(shù)據(jù)躲履,因此應(yīng)盡量不使用事務(wù)查詢數(shù)據(jù)见间,避免占用過量的系統(tǒng)資源。
  4. 在事務(wù)處理過程中盡量不要出現(xiàn)等待用戶輸入的操作:在處理事務(wù)的過程中工猜,如需要等待用戶輸入數(shù)據(jù)米诉,事務(wù)會(huì)長時(shí)間地占用資源,有可能造成系統(tǒng)阻塞篷帅。

MySQL事務(wù)自動(dòng)提交

MySQL 默認(rèn)開啟事務(wù)自動(dòng)提交模式史侣,即除非顯式的開啟事務(wù)(BEGIN 或 START TRANSACTION)拴泌,否則每條 SOL 語句都會(huì)被當(dāng)做一個(gè)單獨(dú)的事務(wù)自動(dòng)執(zhí)行。但有些情況下惊橱,我們需要關(guān)閉事務(wù)自動(dòng)提交來保證數(shù)據(jù)的一致性蚪腐。

在 MySQL 中,可以通過 SHOW VARIABLES 語句查看當(dāng)前事務(wù)自動(dòng)提交模式税朴,如下所示:

mysql> SHOW VARIABLES LIKE 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
1 row in set, 1 warning (0.04 sec)

結(jié)果顯示回季,autocommit 的值是 ON,表示系統(tǒng)開啟自動(dòng)提交模式正林。

在 MySQL 中泡一,可以使用 SET autocommit 語句設(shè)置事務(wù)的自動(dòng)提交模式,語法格式如下:

SET autocommit = 0|1|ON|OFF;

對取值的說明:

  • 值為 0 和值為 OFF:關(guān)閉事務(wù)自動(dòng)提交觅廓。如果關(guān)閉自動(dòng)提交鼻忠,用戶將會(huì)一直處于某個(gè)事務(wù)中,只有提交或回滾后才會(huì)結(jié)束當(dāng)前事務(wù)杈绸,重新開始一個(gè)新事務(wù)帖蔓。
  • 值為 1 和值為 ON:開啟事務(wù)自動(dòng)提交。如果開啟自動(dòng)提交瞳脓,則每執(zhí)行一條 SQL 語句塑娇,事務(wù)都會(huì)提交一次。

關(guān)閉自動(dòng)提交后篡殷,該位置會(huì)作為一個(gè)事務(wù)起點(diǎn)钝吮,直到執(zhí)行 COMMIT 語句和 ROLLBACK 語句后埋涧,該事務(wù)才結(jié)束板辽。結(jié)束之后,這就是下一個(gè)事務(wù)的起點(diǎn)棘催。

關(guān)閉自動(dòng)提交功能后劲弦,只用當(dāng)執(zhí)行 COMMIT 命令后,MySQL 才將數(shù)據(jù)表中的資料提交到數(shù)據(jù)庫中醇坝。如果執(zhí)行 ROLLBACK 命令邑跪,數(shù)據(jù)將會(huì)被回滾。如果不提交事務(wù)呼猪,而終止 MySQL 會(huì)話画畅,數(shù)據(jù)庫將會(huì)自動(dòng)執(zhí)行回滾操作。

使用 BEGIN 或 START TRANSACTION 開啟一個(gè)事務(wù)之后宋距,自動(dòng)提交將保持禁用狀態(tài)轴踱,直到使用 COMMIT 或 ROLLBACK 結(jié)束事務(wù)。之后谚赎,自動(dòng)提交模式會(huì)恢復(fù)到之前的狀態(tài)淫僻,即如果 BEGIN 前 autocommit = 1诱篷,則完成本次事務(wù)后 autocommit 還是 1。如果 BEGIN 前 autocommit = 0雳灵,則完成本次事務(wù)后 autocommit 還是 0棕所。

MySQL事務(wù)隔離級別詳解

MySQL 事務(wù)的四大特性,其中事務(wù)的隔離性就是指當(dāng)多個(gè)事務(wù)同時(shí)運(yùn)行時(shí)悯辙,各事務(wù)之間相互隔離琳省,不可互相干擾。如果事務(wù)沒有隔離性躲撰,就容易出現(xiàn)臟讀岛啸、不可重復(fù)讀和幻讀等情況。為了保證并發(fā)時(shí)操作數(shù)據(jù)的正確性茴肥,數(shù)據(jù)庫都會(huì)有事務(wù)隔離級別的概念坚踩。

  1. 臟讀:是指一個(gè)事務(wù)正在訪問數(shù)據(jù),并且對數(shù)據(jù)進(jìn)行了修改瓤狐,這種修改還沒有提交到數(shù)據(jù)庫中瞬铸,這時(shí),另外一個(gè)事務(wù)也訪問這個(gè)數(shù)據(jù)础锐,然后使用了這個(gè)數(shù)據(jù)嗓节。
  2. 不可重復(fù)讀:是指在一個(gè)事務(wù)內(nèi),多次讀取同一個(gè)數(shù)據(jù)皆警。在這個(gè)事務(wù)還沒有結(jié)束時(shí)拦宣,另外一個(gè)事務(wù)也訪問了該同一數(shù)據(jù)。那么信姓,在第一個(gè)事務(wù)中的兩次讀數(shù)據(jù)之間鸵隧,由于第二個(gè)事務(wù)的修改,那么第一個(gè)事務(wù)兩次讀到的的數(shù)據(jù)可能是不一樣的意推。這樣在一個(gè)事務(wù)內(nèi)兩次讀到的數(shù)據(jù)是不一樣的豆瘫,因此稱為是不可重復(fù)讀。
  3. 幻讀:是指當(dāng)事務(wù)不是獨(dú)立執(zhí)行時(shí)發(fā)生的一種現(xiàn)象菊值,
    • 例如第一個(gè)事務(wù)對一個(gè)表中的數(shù)據(jù)進(jìn)行了修改外驱,這種修改涉及到表中的全部數(shù)據(jù)行。同時(shí)腻窒,第二個(gè)事務(wù)也修改這個(gè)表中的數(shù)據(jù)昵宇,這種修改是向表中插入一行新數(shù)據(jù)。那么儿子,以后就會(huì)發(fā)生操作第一個(gè)事務(wù)的用戶發(fā)現(xiàn)表中還有沒有修改的數(shù)據(jù)行瓦哎,就好象發(fā)生了幻覺一樣。

為了解決以上這些問題,標(biāo)準(zhǔn) SQL 定義了 4 類事務(wù)隔離級別杭煎,用來指定事務(wù)中的哪些數(shù)據(jù)改變是可見的恩够,哪些數(shù)據(jù)改變是不可見的。

MySQL 包括的事務(wù)隔離級別如下:

  • 讀未提交(READ UNCOMITTED)
  • 讀提交(READ COMMITTED)
  • 可重復(fù)讀(REPEATABLE READ)
  • 串行化(SERIALIZABLE)

MySQL 事務(wù)隔離級別可能產(chǎn)生的問題如下表所示:

隔離級別 臟讀 不可重復(fù)讀 幻讀
READ UNCOMITTED 讀未提交
READ COMMITTED 讀提交 ×
REPEATABLE READ 可重復(fù)讀 × ×
SERIALIZABLE 串行化 × × ×

MySQL 的事務(wù)的隔離級別由低到高分別為 READ UNCOMITTED羡铲、READ COMMITTED蜂桶、REPEATABLE READ、SERIALIZABLE也切。低級別的隔離級別可以支持更高的并發(fā)處理扑媚,同時(shí)占用的系統(tǒng)資源更少。

讀未提交(READ UNCOMITTED雷恃,RU)

顧名思義疆股,讀未提交就是可以讀到未提交的內(nèi)容

如果一個(gè)事務(wù)讀取到了另一個(gè)未提交事務(wù)修改過的數(shù)據(jù)倒槐,那么這種隔離級別就稱之為讀未提交旬痹。

在該隔離級別下,所有事務(wù)都可以看到其它未提交事務(wù)的執(zhí)行結(jié)果讨越。因?yàn)樗男阅芘c其他隔離級別相比沒有高多少两残,所以一般情況下,該隔離級別在實(shí)際應(yīng)用中很少使用把跨。

  • 當(dāng) MySQL 的事務(wù)隔離級別為 READ UNCOMITTED 時(shí)人弓,首先分別在 A 窗口和 B 窗口中開啟事務(wù),在 B 窗口中的事務(wù)更新但未提交之前着逐, A 窗口中的事務(wù)就已經(jīng)讀取到了更新后的數(shù)據(jù)崔赌。但由于 B 窗口中的事務(wù)回滾了,所以 A 事務(wù)出現(xiàn)了臟讀現(xiàn)象耸别。

使用讀提交隔離級別可以解決實(shí)例中產(chǎn)生的臟讀問題健芭。

讀提交(READ COMMITTED,RC)

顧名思義太雨,讀提交就是只能讀到已經(jīng)提交了的內(nèi)容吟榴。

如果一個(gè)事務(wù)只能讀取到另一個(gè)已提交事務(wù)修改過的數(shù)據(jù),并且其它事務(wù)每對該數(shù)據(jù)進(jìn)行一次修改并提交后囊扳,該事務(wù)都能查詢得到最新值,那么這種隔離級別就稱之為讀提交兜看。

該隔離級別滿足了隔離的簡單定義:一個(gè)事務(wù)從開始到提交前所做的任何改變都是不可見的锥咸,事務(wù)只能讀取到已經(jīng)提交的事務(wù)所做的改變。

這是大多數(shù)數(shù)據(jù)庫系統(tǒng)的默認(rèn)事務(wù)隔離級別(例如 Oracle细移、SQL Server)搏予,但不是 MySQL 默認(rèn)的。

  • 當(dāng) MySQL 的事務(wù)隔離級別為 READ COMMITTED 時(shí)弧轧,首先分別在 A 窗口和 B 窗口中開啟事務(wù)雪侥,在 B 窗口中的事務(wù)更新并提交后碗殷,A 窗口中的事務(wù)讀取到了更新后的數(shù)據(jù)。在該過程中速缨,A 窗口中的事務(wù)必須要等待 B 窗口中的事務(wù)提交后才能讀取到更新后的數(shù)據(jù)锌妻,這樣就解決了臟讀問題。而處于 A 窗口中的事務(wù)出現(xiàn)了不同的查詢結(jié)果旬牲,即不可重復(fù)讀現(xiàn)象仿粹。

使用可重復(fù)讀隔離級別可以解決實(shí)例中產(chǎn)生的不可重復(fù)讀問題。

可重復(fù)讀(REPEATABLE READ原茅,RR)

顧名思義吭历,可重復(fù)讀是專門針對不可重復(fù)讀這種情況而制定的隔離級別,可以有效的避免不可重復(fù)讀擂橘。

在一些場景中晌区,一個(gè)事務(wù)只能讀取到另一個(gè)已提交事務(wù)修改過的數(shù)據(jù),但是第一次讀過某條記錄后通贞,即使其它事務(wù)修改了該記錄的值并且提交契讲,之后該事務(wù)再讀該條記錄時(shí),讀到的仍是第一次讀到的值滑频,而不是每次都讀到不同的數(shù)據(jù)捡偏。那么這種隔離級別就稱之為可重復(fù)讀。

可重復(fù)讀是 MySQL 的默認(rèn)事務(wù)隔離級別峡迷,它能確保同一事務(wù)的多個(gè)實(shí)例在并發(fā)讀取數(shù)據(jù)時(shí)银伟,會(huì)看到同樣的數(shù)據(jù)行。在該隔離級別下绘搞,如果有事務(wù)正在讀取數(shù)據(jù)彤避,就不允許有其它事務(wù)進(jìn)行修改操作,這樣就解決了可重復(fù)讀問題夯辖。

使用串行化隔離級別可以解決實(shí)例中產(chǎn)生的幻讀問題琉预。

串行化(SERIALIZABLE)

如果一個(gè)事務(wù)先根據(jù)某些條件查詢出一些記錄,之后另一個(gè)事務(wù)又向表中插入了符合這些條件的記錄蒿褂,原先的事務(wù)再次按照該條件查詢時(shí)圆米,能把另一個(gè)事務(wù)插入的記錄也讀出來。那么這種隔離級別就稱之為串行化啄栓。

SERIALIZABLE 是最高的事務(wù)隔離級別娄帖,主要通過強(qiáng)制事務(wù)排序來解決幻讀問題。簡單來說昙楚,就是在每個(gè)讀取的數(shù)據(jù)行上加上共享鎖實(shí)現(xiàn)近速,這樣就避免了臟讀、不可重復(fù)讀和幻讀等問題。但是該事務(wù)隔離級別執(zhí)行效率低下削葱,且性能開銷也最大奖亚,所以一般情況下不推薦使用。

MySQL查看和修改事務(wù)隔離級別

查看事務(wù)隔離級別

在 MySQL 中析砸,可以通過show variables like '%tx_isolation%'select @@tx_isolation;語句來查看當(dāng)前事務(wù)隔離級別昔字。

查看當(dāng)前事務(wù)隔離級別的 SQL 語句和運(yùn)行結(jié)果如下:

mysql> show variables like '%tx_isolation%';
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| tx_isolation  | REPEATABLE-READ |
+---------------+-----------------+
1 row in set, 1 warning (0.17 sec)
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)

結(jié)果顯示,目前 MySQL 的事務(wù)隔離級別是 REPEATABLE-READ干厚。

另外李滴,還可以使用下列語句分別查詢?nèi)趾蜁?huì)話的事務(wù)隔離級別:

SELECT @@global.tx_isolation;
SELECT @@session.tx_isolation;

提示:在MySQL 8.0.3 中,tx_isolation 變量被 transaction_isolation 變量替換了蛮瞄。在 MySQL 8.0.3 版本中查詢事務(wù)隔離級別所坯,只要把上述查詢語句中的 tx_isolation 變量替換成 transaction_isolation 變量即可。

修改事務(wù)隔離級別

MySQL 提供了 SET TRANSACTION 語句挂捅,該語句可以改變單個(gè)會(huì)話或全局的事務(wù)隔離級別芹助。語法格式如下:

SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}

其中,SESSION 和 GLOBAL 關(guān)鍵字用來指定修改的事務(wù)隔離級別的范圍:

  • SESSION:表示修改的事務(wù)隔離級別將應(yīng)用于當(dāng)前 session(當(dāng)前 cmd 窗口)內(nèi)的所有事務(wù)闲先;
  • GLOBAL:表示修改的事務(wù)隔離級別將應(yīng)用于所有 session(全局)中的所有事務(wù)状土,且當(dāng)前已經(jīng)存在的 session 不受影響;
  • 如果省略 SESSION 和 GLOBAL伺糠,表示修改的事務(wù)隔離級別將應(yīng)用于當(dāng)前 session 內(nèi)的下一個(gè)還未開始的事務(wù)蒙谓。

任何用戶都能改變會(huì)話的事務(wù)隔離級別,但是只有擁有 SUPER 權(quán)限的用戶才能改變?nèi)值氖聞?wù)隔離級別训桶。

如果使用普通用戶修改全局事務(wù)隔離級別累驮,就會(huì)提示需要超級權(quán)限才能執(zhí)行此操作的錯(cuò)誤信息:

MySQL鎖機(jī)制

為了保證數(shù)據(jù)并發(fā)訪問時(shí)的一致性和有效性,任何一個(gè)數(shù)據(jù)庫都存在鎖機(jī)制舵揭。鎖機(jī)制的優(yōu)劣直接影響到數(shù)據(jù)庫的并發(fā)處理能力和系統(tǒng)性能谤专,所以鎖機(jī)制也就成為了各種數(shù)據(jù)庫的核心技術(shù)之一。

鎖機(jī)制是為了解決數(shù)據(jù)庫的并發(fā)控制問題而產(chǎn)生的午绳。如在同一時(shí)刻置侍,客戶端對同一個(gè)表做更新或查詢操作,為了保證數(shù)據(jù)的一致性拦焚,必須對并發(fā)操作進(jìn)行控制蜡坊。同時(shí),鎖機(jī)制也為實(shí)現(xiàn) MySQL 的各個(gè)隔離級別提供了保證耕漱。

可以將鎖機(jī)制理解為使各種資源在被并發(fā)訪問時(shí)變得有序所設(shè)計(jì)的一種規(guī)則算色。

如何保證數(shù)據(jù)并發(fā)訪問的一致性、有效性是所有數(shù)據(jù)庫必須解決的一個(gè)問題螟够,鎖沖突也是影響數(shù)據(jù)庫并發(fā)訪問性能的一個(gè)重要因素。從這個(gè)角度來說,鎖對數(shù)據(jù)庫顯得尤其重要妓笙,也更加復(fù)雜若河。

按鎖級別分類,可分為共享鎖寞宫、排他鎖和意向鎖萧福。也可以按鎖粒度分類,可分為行級鎖辈赋、表級鎖和頁級鎖鲫忍。

共享鎖

共享鎖的代號是 S,是 Share 的縮寫钥屈,也可稱為讀鎖悟民。是一種可以查看但無法修改和刪除的數(shù)據(jù)鎖。

共享鎖的鎖粒度是行或者元組(多個(gè)行)篷就。一個(gè)事務(wù)獲取了共享鎖之后射亏,可以對鎖定范圍內(nèi)的數(shù)據(jù)執(zhí)行讀操作。會(huì)阻止其它事務(wù)獲得相同數(shù)據(jù)集的排他鎖竭业。

排他鎖

排他鎖的代號是 X智润,是 eXclusive 的縮寫,也可稱為寫鎖未辆,是基本的鎖類型窟绷。

排他鎖的粒度與共享鎖相同,也是行或者元組咐柜。一個(gè)事務(wù)獲取了排他鎖之后兼蜈,可以對鎖定范圍內(nèi)的數(shù)據(jù)執(zhí)行寫操作。允許獲得排他鎖的事務(wù)更新數(shù)據(jù)炕桨,阻止其它事務(wù)取得相同數(shù)據(jù)集的共享鎖和排他鎖饭尝。

  • 如有兩個(gè)事務(wù) A 和 B,如果事務(wù) A 獲取了一個(gè)元組的共享鎖献宫,事務(wù) B 還可以立即獲取這個(gè)元組的共享鎖钥平,但不能立即獲取這個(gè)元組的排他鎖,必須等到事務(wù) A 釋放共享鎖之后才可以姊途。
  • 如果事務(wù) A 獲取了一個(gè)元組的排他鎖涉瘾,事務(wù) B 不能立即獲取這個(gè)元組的共享鎖,也不能立即獲取這個(gè)元組的排他鎖捷兰,必須等到 A 釋放排他鎖之后才可以立叛。

意向鎖

為了允許行鎖和表鎖共存,實(shí)現(xiàn)多粒度鎖機(jī)制贡茅,InnoDB 還有兩種內(nèi)部使用的意向鎖秘蛇。

意向鎖是一種表鎖其做,鎖定的粒度是整張表,分為意向共享鎖(IS)和意向排他鎖(IX)兩類赁还。

意向共享鎖表示一個(gè)事務(wù)有意對數(shù)據(jù)上共享鎖或者排他鎖妖泄。“有意”表示事務(wù)想執(zhí)行操作但還沒有真正執(zhí)行艘策。

鎖和鎖之間的關(guān)系蹈胡,要么是相容的,要么是互斥的朋蔫。

  • 鎖 a 和鎖 b 相容是指:操作同樣一組數(shù)據(jù)時(shí)罚渐,如果事務(wù) t1 獲取了鎖 a,另一個(gè)事務(wù) t2 還可以獲取鎖 b驯妄;
  • 鎖 a 和鎖 b 互斥是指:操作同樣一組數(shù)據(jù)時(shí)荷并,如果事務(wù) t1 獲取了鎖 a,另一個(gè)事務(wù) t2 在 t1 釋放鎖 a 之前無法釋放鎖 b富玷。

鎖模式的兼容情況

其中共享鎖璧坟、排他鎖、意向共享鎖赎懦、意向排他鎖相互之間的兼容/互斥關(guān)系如下表所示雀鹃,其中 Y 表示相容,N 表示互斥励两。

參數(shù) X S IX IS
X(排他鎖) N N N N
S(共享鎖) N Y N Y
IX(意向排他鎖) N N Y Y
IS(意向共享鎖) N Y Y Y

如果一個(gè)事務(wù)請求的鎖模式與當(dāng)前的鎖兼容黎茎,InnoDB 就將請求的鎖授予該事務(wù);反之当悔,如果兩者不兼容傅瞻,該事務(wù)就要等待鎖釋放。

為了盡可能提高數(shù)據(jù)庫的并發(fā)量盲憎,需每次鎖定的數(shù)據(jù)范圍越小越好嗅骄,越小的鎖其耗費(fèi)的系統(tǒng)資源越多,系統(tǒng)性能下降饼疙。為在高并發(fā)響應(yīng)和系統(tǒng)性能兩方面進(jìn)行平衡溺森,這樣就產(chǎn)生了“鎖粒度”的概念。

MySQL表鎖窑眯、行鎖和頁鎖

MySQL 按鎖的粒度可以細(xì)分為行級鎖屏积、頁級鎖和表級鎖。我們可以將鎖粒度理解成鎖范圍磅甩。

表級鎖(table lock)

表級鎖為表級別的鎖定炊林,會(huì)鎖定整張表,可以很好的避免死鎖卷要,是 MySQL 中最大顆粒度的鎖定機(jī)制渣聚。

一個(gè)用戶在對表進(jìn)行寫操作(插入独榴、刪除、更新等)時(shí)饵逐,需要先獲得寫鎖括眠,這會(huì)阻塞其它用戶對該表的所有讀寫操作彪标。沒有寫鎖時(shí)倍权,其它讀取的用戶才能獲得讀鎖,讀鎖之間是不相互阻塞的捞烟。

表級鎖最大的特點(diǎn)就是實(shí)現(xiàn)邏輯非常簡單薄声,帶來的系統(tǒng)負(fù)面影響最小。所以獲取鎖和釋放鎖的速度很快题画。當(dāng)然默辨,鎖定顆粒度大帶來最大的負(fù)面影響就是出現(xiàn)鎖定資源爭用的概率會(huì)很高,致使并發(fā)度大打折扣苍息。

不過在某些特定的場景中缩幸,表級鎖也可以有良好的性能。

  • 例如竞思,READ LOCAL 表級鎖支持某些類型的并發(fā)寫操作表谊。另外,寫鎖也比讀鎖有更高的優(yōu)先級盖喷,因此一個(gè)寫鎖請求可能會(huì)被插入到讀鎖隊(duì)列的前面(寫鎖可以插入到鎖隊(duì)列中讀鎖的前面爆办,反之讀鎖則不能插入到寫鎖的前面)。

使用表級鎖的主要是 MyISAM课梳,MEMORY距辆,CSV 等一些非事務(wù)性存儲(chǔ)引擎。

盡管存儲(chǔ)引擎可以管理自己的鎖暮刃,MySQL 本身還是會(huì)使用各種有效的表級鎖來實(shí)現(xiàn)不同的目的跨算。

  • 例如,服務(wù)器會(huì)為諸如 ALTER TABLE 之類的語句使用表級鎖椭懊,而忽略存儲(chǔ)引擎的鎖機(jī)制诸蚕。

頁級鎖(page lock)

頁級鎖是 MySQL 中比較獨(dú)特的一種鎖定級別,在其他數(shù)據(jù)庫管理軟件中并不常見灾搏。

頁級鎖的顆粒度介于行級鎖與表級鎖之間挫望,所以獲取鎖定所需要的資源開銷,以及所能提供的并發(fā)處理能力同樣也是介于上面二者之間狂窑。另外媳板,頁級鎖和行級鎖一樣,會(huì)發(fā)生死鎖泉哈。

頁級鎖主要應(yīng)用于 BDB 存儲(chǔ)引擎蛉幸。

行級鎖(row lock)

行級鎖的鎖定顆粒度在 MySQL 中是最小的破讨,只針對操作的當(dāng)前行進(jìn)行加鎖,所以行級鎖發(fā)生鎖定資源爭用的概率也最小奕纫。

行級鎖能夠給予應(yīng)用程序盡可能大的并發(fā)處理能力提陶,從而提高需要高并發(fā)應(yīng)用系統(tǒng)的整體性能。雖然行級鎖在并發(fā)處理能力上面有較大的優(yōu)勢匹层,但也因此帶來了不少弊端隙笆。

由于鎖定資源的顆粒度很小,所以每次獲取鎖和釋放鎖需要做的事情也就更多升筏,帶來的消耗自然也就更大撑柔。此外,行級鎖也最容易發(fā)生死鎖您访。所以說行級鎖最大程度地支持并發(fā)處理的同時(shí)铅忿,也帶來了最大的鎖開銷。

行級鎖主要應(yīng)用于 InnoDB 存儲(chǔ)引擎灵汪。

隨著鎖定資源顆粒度的減小檀训,鎖定相同數(shù)據(jù)量的數(shù)據(jù)所需要消耗的內(nèi)存數(shù)量也越來越多,實(shí)現(xiàn)算法也會(huì)越來越復(fù)雜享言。不過峻凫,隨著鎖定資源顆粒度的減小,應(yīng)用程序的訪問請求遇到鎖等待的可能性也會(huì)隨之降低担锤,系統(tǒng)整體并發(fā)度也會(huì)隨之提升蔚晨。

MySQL 3 種鎖的特性

表級鎖 行級鎖 頁級鎖
開銷 介于表級鎖和行級鎖之間
加鎖 介于表級鎖和行級鎖之間
死鎖 不會(huì)出現(xiàn)死鎖 會(huì)出現(xiàn)死鎖 會(huì)出現(xiàn)死鎖
鎖粒度 介于表級鎖和行級鎖之間
并發(fā)度 一般

從上述特點(diǎn)可見,很難籠統(tǒng)的說哪種鎖更好肛循,只能具體應(yīng)用具體分析铭腕。

從鎖的角度來說,表級鎖適合以查詢?yōu)橹鞫嗫罚挥猩倭堪此饕龡l件更新數(shù)據(jù)的應(yīng)用累舷,如 Web 應(yīng)用。而行級鎖更適合于有大量按索引條件夹孔,同時(shí)又有并發(fā)查詢的應(yīng)用被盈,如一些在線事務(wù)處理(OLTP)系統(tǒng)。

MySQL InnoDB行鎖

在 MySQL 中搭伤,InnoDB 行鎖通過給索引上的索引項(xiàng)加鎖來實(shí)現(xiàn)只怎,如果沒有索引,InnoDB 將通過隱藏的聚簇索引來對記錄加鎖怜俐。

InnoDB 支持 3 種行鎖定方式:

  • 行鎖(Record Lock):直接對索引項(xiàng)加鎖身堡。
  • 間隙鎖(Gap Lock):鎖加在索引項(xiàng)之間的間隙,也可以是第一條記錄前的“間隙”或最后一條記錄后的“間隙”拍鲤。
  • Next-Key Lock:行鎖與間隙鎖組合起來用就叫做 Next-Key Lock贴谎。 前兩種的組合汞扎,對記錄及其前面的間隙加鎖。

默認(rèn)情況下擅这,InnoDB 工作在可重復(fù)讀(默認(rèn)隔離級別)下澈魄,并且以 Next-Key Lock 的方式對數(shù)據(jù)行進(jìn)行加鎖,這樣可以有效防止幻讀的發(fā)生仲翎。

Next-Key Lock 是行鎖與間隙鎖的組合痹扇,這樣,當(dāng) InnoDB 掃描索引項(xiàng)的時(shí)候谭确,會(huì)首先對選中的索引項(xiàng)加上行鎖(Record Lock)帘营,再對索引項(xiàng)兩邊的間隙(向左掃描掃到第一個(gè)比給定參數(shù)小的值, 向右掃描掃到第一個(gè)比給定參數(shù)大的值逐哈, 然后以此為界,構(gòu)建一個(gè)區(qū)間)加上間隙鎖(Gap Lock)问顷。如果一個(gè)間隙被事務(wù) T1 加了鎖昂秃,其它事務(wù)不能在這個(gè)間隙插入記錄。

要禁止間隙鎖的話杜窄,可以把隔離級別降為讀已提交(READ COMMITTED)肠骆,或者開啟參數(shù) innodb_locks_unsafe_for_binlog。

注意:以上語句描述的情況塞耕,與 MySQL 所設(shè)置的事務(wù)隔離級別有較大的關(guān)系蚀腿。

開啟一個(gè)事務(wù)時(shí),InnoDB 存儲(chǔ)引擎會(huì)在更新的記錄上加行級鎖扫外,此時(shí)其它事務(wù)不可以更新被鎖定的記錄莉钙。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市筛谚,隨后出現(xiàn)的幾起案子磁玉,更是在濱河造成了極大的恐慌,老刑警劉巖驾讲,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蚊伞,死亡現(xiàn)場離奇詭異,居然都是意外死亡吮铭,警方通過查閱死者的電腦和手機(jī)时迫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谓晌,“玉大人掠拳,你說我怎么就攤上這事≡眩” “怎么了碳想?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵烧董,是天一觀的道長。 經(jīng)常有香客問我胧奔,道長逊移,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任龙填,我火速辦了婚禮胳泉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘岩遗。我一直安慰自己扇商,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布宿礁。 她就那樣靜靜地躺著案铺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪梆靖。 梳的紋絲不亂的頭發(fā)上控汉,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天,我揣著相機(jī)與錄音返吻,去河邊找鬼姑子。 笑死,一個(gè)胖子當(dāng)著我的面吹牛测僵,可吹牛的內(nèi)容都是我干的街佑。 我是一名探鬼主播,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼捍靠,長吁一口氣:“原來是場噩夢啊……” “哼沐旨!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起剂公,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤希俩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后纲辽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體颜武,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年拖吼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鳞上。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,015評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡吊档,死狀恐怖篙议,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤鬼贱,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布移怯,位于F島的核電站,受9級特大地震影響这难,放射性物質(zhì)發(fā)生泄漏舟误。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一姻乓、第九天 我趴在偏房一處隱蔽的房頂上張望嵌溢。 院中可真熱鬧,春花似錦蹋岩、人聲如沸赖草。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽秧骑。三九已至,卻和暖如春禁偎,著一層夾襖步出監(jiān)牢的瞬間腿堤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工如暖, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人忌堂。 一個(gè)月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓狠持,卻偏偏與公主長得像井仰,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評論 2 355