MySQL存儲引擎揩懒、事務(wù)日志并發(fā)訪問以及隔離級別

MySQL存儲引擎

  • MySQL是插件式存儲存儲引擎漏健,支持多種存儲引擎

    • 常見的存儲引擎有:MyISAM, Aria, InnoDB, MRG_MYISAM, CSV, BLACKHOLE, MEMORY, PERFORMANCE_SCHEMA, ARCHIVE, FEDERATED

      mysql> SHOW ENGINES;   #查看支持多少種存儲引擎
      *************************** 1. row ***************************
        Engine: FEDERATED                 #引擎名稱
        Support: NO                         #是否支持
       Comment: Federated MySQL storage engine    #簡要注釋
      Transactions: NULL                     #是否支持事務(wù)功能
          XA: NULL                     #是否支持分布式事務(wù)功能
      Savepoints: NULL                     # 是否支持保存點功能 
        *************************** 2. row ***************************
      

      ...

  • 存儲引擎是表級別的概念婉刀,因此又稱為“表類型”损话;不建議在同一個庫中的表上使用不同的ENGINE;

      CREATE TABLE ... ENGINE[=]STORAGE_ENGINE_NAME ...
      SHOW TABLE STATUS 
    

1. InnoDB存儲引擎

InnoDB存儲引擎翎碑,把數(shù)據(jù)存儲在一個文件中谬返,是個黑盒,根varnish是一樣日杈,varnish中的數(shù)據(jù)緩存都存儲在一個文件中遣铝,但其內(nèi)部完全有自組織有序的結(jié)果從外部看來就是一個文件,內(nèi)部可以有自己的元數(shù)據(jù)莉擒,數(shù)據(jù)是構(gòu)建在文件系統(tǒng)之上的文件系統(tǒng)蚪拦;而InnoDB也是這樣匆绣,默認情況下可以將n張表放在一個表空間里媒殉,在外部看來就是一個表交播,其內(nèi)部存放了n張表甚至存放了n張表的索引檀何;不過把n張表的索引放在同一表中很難實現(xiàn)高級功能蝇裤;比如像單表導(dǎo)入導(dǎo)出等;因此频鉴,這就是為什么在安裝MariaDB時栓辜,都要求使用innodb_file_per_table這表示每張表使用一個表空間;

InnoDB的表空間為了能跨文件系統(tǒng)(分區(qū))垛孔,InnoDB的表空間背后所對應(yīng)的文件 可以不止一個藕甩,而且還可以自動增長;表空間剛創(chuàng)建時周荐,就占用固定大小的空間狭莱,如果再許愿空間時,就又占用固定大小的空間概作,用不用都占用腋妙;可理解為是基于步進的方式進行劃分;InnoDB將所有的表和索引放在一個表空間中讯榕;

如果所有表和數(shù)據(jù)都存儲在一個表空間中時骤素,表空間文件是存儲在datadir定義的目錄中的匙睹;
如果每張表單獨存儲在一個表空間中,則表空間文件是放置在數(shù)據(jù)庫目錄下济竹,而不是數(shù)據(jù)目錄下痕檬;例如有一個數(shù)據(jù)庫叫mydb就相當于在數(shù)據(jù)庫目錄下創(chuàng)建一個mydb的目錄而已;
當然數(shù)據(jù)庫目錄有可能在數(shù)據(jù)目錄下的子目錄送浊;

MariaDB [(none)]> SHOW ENGINES\G;
...
*************************** 6. row ***************************
      Engine: InnoDB
     Support: DEFAULT
     Comment: Percona-XtraDB, Supports transactions, row-level locking, and foreign keys
Transactions: YES
          XA: YES
  Savepoints: YES
  • 數(shù)據(jù)存儲于“表空間(table space)”中梦谜,是個黑盒:有兩種管理方式:
    (1) 所有數(shù)據(jù)庫中的所有類型為InnoDB的表的數(shù)據(jù)和索引存儲于同一個表空間中;

    • 表空間文件:存儲在datadir定義的目錄下罕袋;
    • 表現(xiàn)出的文件為:ibddata1改淑,ibddata2,...
      (2) 每個表單獨使用一個表空間存儲表的數(shù)據(jù)和索引浴讯;使用innodb_file_per_table=ON開啟朵夏;
    • 數(shù)據(jù)文件(存儲數(shù)據(jù)和索引)名:tb1_name.frm
    • 每張表由2個文件組成:tb1_name.ldb和tb1_name.frm
    • 文件存儲于數(shù)據(jù)庫目錄中
      注:基于第一種方式管理時,所有數(shù)據(jù)庫的InnoDB表將使用同一個表空間榆纽,例如有10個庫仰猖,每個庫中有100張表,都放在同一個表空間中奈籽,于后期管理無益饥侵。
  • InnoDB存儲引擎是事務(wù)性存儲引擎,適合處理大量的短期任務(wù)衣屏;

    • 基于MVCC(Mutli Version Concurrenvy Contro躏升,多版本并發(fā)控制)支持高并發(fā),支持所有的四個隔離級別狼忱;默認支持間隙鎖防止幻讀膨疏;
    • 使用聚簇索引(一般是主鍵索引);
      • 一張表的聚簇索引只能有一個钻弄;索引在哪數(shù)據(jù)就在哪里
    • 支持自適應(yīng)hash索引佃却;
    • 鎖粒度:行級鎖,間隙鎖窘俺;

注意:級別越高事務(wù)發(fā)生沖突性越小饲帅,事務(wù)安全性越高但并發(fā)性能就越低;

注:MVCC瘤泪,multi version concurrency control:多版本并發(fā)訪問控制灶泵,它就是類似于lvm的快照功能;也就意味著对途,當啟動n個事務(wù)時丘逸,每一個事務(wù),都針對于mysql當中的InnoDB存儲引擎現(xiàn)有數(shù)據(jù)做一個快照掀宋; 每一個快照深纲,通過快照過去訪問時間點是一致的仲锄,所以現(xiàn)在要啟動一個事務(wù),就對InnoDB數(shù)據(jù)集做個快照湃鹊,就在快照基礎(chǔ)上做操作儒喊;因此有50個事務(wù)為了彼此間不受影響,每個事務(wù)啟動一次做一個快照币呵。
但是怀愧,這病不意味著就沒有沖突,想象以下余赢,如果第一個快照和第二個也快照了芯义,兩個操作同一個數(shù)據(jù)集,一個刪了一行妻柒,而第二個事務(wù)把這個行改了扛拨,此時就會出現(xiàn)問題,所以举塔,必須有隔離機制來實現(xiàn)所謂的事務(wù)隔離绑警;
而事務(wù)隔離中最核心組件就是鎖;這么一來事務(wù)也沒法并發(fā)了央渣,既然鎖了计盒,看上去事務(wù)同時啟動,但是還得等待一個個完成芽丹;所以北启,隔離級別至關(guān)重要了;


另:percona公司對mysql做了二次開發(fā)拔第,服務(wù)器版本為percona-server咕村,把InnoDB改進為XtraDB存儲引擎,mariadb使用了XtraDB引擎楼肪,但是名稱依然叫InnoDB

總結(jié)InnoDB引擎的特性:
  • 存儲數(shù)據(jù):表空間
  • 并發(fā):MVCC培廓,間隙鎖
  • 索引:聚集索引惹悄、輔助索引
  • 性能:預(yù)讀操作春叫、自適應(yīng)hash索引、插入操作緩存區(qū)
  • 備份:支持熱備

SHOW ENGINE INNODB STATUS;

2. MyISAM存儲引擎

MyISAM內(nèi)部的復(fù)雜機制很少泣港,特別適應(yīng)于讀多寫少的應(yīng)用暂殖;但是,mysql自己的表当纱,內(nèi)部的元數(shù)據(jù)的庫還是使用的MyISAM存儲引擎呛每;
MyISAM存儲引擎最大特性是支持全文索引,全文索引指的是全文中的每一個關(guān)鍵字都可以被搜索坡氯;
MyISAM在崩潰后無法安全恢復(fù)晨横,有可能會導(dǎo)致某些數(shù)據(jù)丟失洋腮,比如要插入一行數(shù)據(jù),剛插入一般數(shù)據(jù)庫崩潰手形,只能把剛插入的半行刪了啥供,保證數(shù)據(jù)是一致性的;解決辦法是使用MyISAM表修復(fù)工具库糠,會對全表掃描伙狐,一行行掃描,看哪一行中的數(shù)據(jù)不是完整的給它刪了瞬欧,所以這就是崩潰后的恢復(fù)贷屎,如果表要大的話,恢復(fù)時間會非常長艘虎;索引說可以接受較長時間的修復(fù)操作才能使用MyISAM;這個較長時間還是指的較小的表唉侄,如果表答可能修復(fù)一天都有可能。
MariaDB雖然支持MyISAM存儲引擎但是顷帖,默認對于MyISAM而言使用的是Aria存儲引擎美旧,其實就是MyISAM的增強版,支持崩潰后的安全恢復(fù)贬墩;
MyISAM存儲引擎的文件榴嗅,表和索引是獨立存放的;索引可看出來使用的是非聚集索引陶舞;因此嗽测,每一個索引的葉子節(jié)點,都是個指針肿孵,指向了真正數(shù)據(jù)所在的位置唠粥;這就類似于書中的目錄和后面正文的關(guān)系;

對于InnoDB停做,每張表使用兩個文件一個是用來存儲數(shù)據(jù)和索引的.ibd文件晤愧,一個是用來存儲表格式的.frm格式的文件;而對于MyISAM蛉腌,每張表有三個文件且都放在數(shù)據(jù)庫目錄下而不是datadir=指定的目錄下官份,也就是說的datadir指定的目錄下的子目錄里;

  • tbl_name.frm:表格式定義烙丛;
  • tbl_name.MYD:數(shù)據(jù)文件舅巷;
  • tbl_name.MYI:索引文件;
MariaDB [(none)]> SHOW ENGINES\G;
*************************** 5. row ***************************
      Engine: MyISAM
     Support: YES
     Comment: MyISAM storage engine
Transactions: NO
          XA: NO
  Savepoints: NO
總結(jié)MyISAM存儲引擎特性:
  • 加鎖好并發(fā):支持表級鎖
  • 修復(fù):只能手動或自動修復(fù)(使用工具)河咽、但可能會丟失數(shù)據(jù)钠右;并不是安全恢復(fù)
  • 索引:使用的是非聚集索引
  • 支持延遲更新索引:只是為了提高性能
  • 支持表壓縮:壓縮后表數(shù)據(jù)不能修改
行格式:

{DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT}

  • dynamic: 動態(tài)行
  • fixed:固定行
  • compressed:壓縮行
  • compact:緊致行
  • redundent:冗余行

態(tài)還是固定行取決于表中字段的類型,例如字段的類型是varchar類型長度是可變的忘蟹,如果某一字段使用varchar類型飒房,每行可以不同的長度搁凸;行長度不一樣管理很麻煩,性能比較低狠毯;行的長度一樣只需根據(jù)距離來判斷下一行在什么位置就可以了坪仇;

以上InnoDB和MyISAM是mysql中最為經(jīng)典的兩種存儲引擎;

MariaDB [hellodb]> SHOW ENGINES;  #查看所有支持的存儲引擎
+--------------------+---------+----------------------------------------------------------------------------+--------------+------+------------+
| Engine             | Support | Comment                                                                    | Transactions | XA   | Savepoints |
+--------------------+---------+----------------------------------------------------------------------------+--------------+------+------------+
| MEMORY             | YES     | Hash based, stored in memory, useful for temporary tables                  | NO           | NO   | NO         |
| MRG_MYISAM         | YES     | Collection of identical MyISAM tables                                      | NO           | NO   | NO         |
| CSV                | YES     | CSV storage engine                                                         | NO           | NO   | NO         |
| BLACKHOLE          | YES     | /dev/null storage engine (anything you write to it disappears)             | NO           | NO   | NO         |
| MyISAM             | YES     | MyISAM storage engine                                                      | NO           | NO   | NO         |
| InnoDB             | DEFAULT | Percona-XtraDB, Supports transactions, row-level locking, and foreign keys | YES          | YES  | YES        |
| ARCHIVE            | YES     | Archive storage engine                                                     | NO           | NO   | NO         |
| FEDERATED          | YES     | FederatedX pluggable storage engine                                        | 


MariaDB [hellodb]> SHOW GLOBAL VARIABLES LIKE '%STORAGE%';  #查看默認存儲引擎
+------------------------+--------+
| Variable_name          | Value  |
+------------------------+--------+
| default_storage_engine | InnoDB |
| storage_engine         | InnoDB |
+------------------------+--------+

3. 其他存儲引擎

  • CSV:將普通的CSV文件(字段基于逗號分隔)作為MySQL表使用垃你;
    • 所謂CSV文件:一個文件中也是有很多行組成椅文,每一行有很多字段組成,而字段用逗號分隔惜颇,把整個文件當表使用皆刺;
    • CVS文件好處在于可以使用grep、awk凌摄、sed工具直接處理羡蛾,但是由于基于文本存儲的,浮點型數(shù)據(jù)轉(zhuǎn)換為文本字符串存儲后會丟失精度
    • CVS特別適合用于在多個不同的數(shù)據(jù)庫之間共享數(shù)據(jù)時使用
  • MRG_MYISAM:由多個MyISAM表合并成的虛擬表
    • 表可以分割成小表锨亏,就像zabbix中數(shù)據(jù)一樣痴怨,把表分成多個小標按天存放,一天一張表器予,要想刪除時浪藻,直接刪除某天的表即可;每一天的表其實就是一個表分區(qū)table partion
    • 要查詢多張表是合并即可
  • BLACKHOLE:類似于/dev/null乾翔,不真正存儲任何數(shù)據(jù)爱葵,只會在特定場景中使用
    • 對mysql而言blachole stroage engine相當于linux上的/dev/null,索引某張表的存儲引擎是該類型反浓,這個表存儲的所有數(shù)據(jù)都不會產(chǎn)生任何IO萌丈,因為數(shù)據(jù)被丟棄了
    • 只在特定的場景中使用:比如多級架構(gòu)執(zhí)行復(fù)制操作時;
  • MEMORY:基于內(nèi)存存儲雷则,支持hash索引辆雾,表級鎖,常用語臨時表月劈;
  • PERFORMANCE_SCHEMA:類似于Linux/proc目錄度迂,用于存儲mysql的性能數(shù)據(jù);
    • 是關(guān)于mysql性能各類統(tǒng)計的收集存儲的表艺栈,只用來收集mysql運行中的統(tǒng)計數(shù)據(jù)英岭,做性能評估湾盒,或者是有助于優(yōu)化器優(yōu)化湿右;
    • 表中的統(tǒng)計數(shù)據(jù)只對當前有效,一旦mysql停機罚勾,這個表就作廢變?yōu)榭盏囊闳耍瑔雍缶蜁粩嗟奶钊牒芏嗍占降呐c性能相關(guān)的數(shù)據(jù)
    • 此存儲引擎用處在于mysql為了達到一切皆sql表的目的吭狡,索引把它內(nèi)部的統(tǒng)計數(shù)據(jù)基于sql接口進行輸出了
  • ARCHIVE:支持SELECT 和INSERT 操作,支持行級鎖和專用緩存區(qū)丈莺;
    • 用于數(shù)據(jù)永久存儲并且當做數(shù)據(jù)倉庫使用划煮;不支持修改操作
  • FEDERATED:類似于MRG_MYISAM,不用支出在于MRG_MYISAM所合并的多張表一定是同一個mysql服務(wù)器上的缔俄,甚至是同一個數(shù)據(jù)庫中的多張表弛秋;但是FEDERATED能把兩個數(shù)據(jù)庫服務(wù)器上的表聯(lián)合在一起使用
    • 用于訪問其它的遠程的MySQL Server的代理接口,它通過創(chuàng)建一個到遠程MySQL Server的客戶端連接俐载,并將查詢語句傳輸至遠程服務(wù)器執(zhí)行蟹略;
    • 自己本地沒有表,但可以把這個當做接口遏佣,所有發(fā)給FEDERATED存儲引擎表的所有語句挖炬,都會基于mysql連接發(fā)給另一個數(shù)據(jù)庫服務(wù)器上另外一張表,而后完成數(shù)據(jù)存茸瓷簟意敛;
      注:FEDERATED也僅支持mariadb;是夸數(shù)據(jù)庫服務(wù)器的角色

4. MariaDB支持的其他存儲引擎

  • OQGraph:支持實體存儲
  • Sphinx SE:搜索引擎
    • 而mariadb支持sphinxSE存儲引擎膛虫,意味著草姻,這個表存儲的所有數(shù)據(jù)都直接基于sphinxSE接口導(dǎo)入到sphinx存儲里了;
  • TokuDB:支持海量數(shù)據(jù)的存儲引擎稍刀,支持原生分布式存儲
  • Cassandra:由facebook研發(fā)碴倾,分布式無中心的存儲;
    • mariadb支持把表存儲Cassandra以后掉丽,沒有在mysql本地存儲跌榔,而是導(dǎo)入到Cassandra表中;
  • CONNECT存儲引擎
  • SQUENCE存儲引擎

MySQL事務(wù)

并發(fā)控制:

鎖是mysql實現(xiàn)并發(fā)訪問控制的重要組件捶障;

  • 為什么要有鎖機制:
    任何文件或數(shù)據(jù)集只要支持并發(fā)訪問模型僧须,就必須基于鎖機制對其機制進行控制;對mysql服務(wù)器项炼,允許多個線程同時連進來支持做讀寫操作請求担平,這樣多個查詢語句就有可能只對同一個數(shù)據(jù)集進行,例如第一個線程對數(shù)據(jù)集中的某行做修改锭部,第二個線程對同一個數(shù)據(jù)集中的同一行做查詢暂论,這樣二者同時操作就會帶來混亂;
    所以拌禾,mysql為了能夠?qū)崿F(xiàn)并發(fā)訪問中避免數(shù)據(jù)讀寫沖突取胎,就必須施加所機制。

  • 鎖類型:

    • 讀鎖:共享鎖,可以共享給其他的讀操作
    • 寫鎖:獨占所闻蛀,其他操作不可讀寫
  • 鎖粒度:

    • 表級鎖:在表級別施加鎖匪傍,并發(fā)性較低;
    • 行級鎖:在行級別施加鎖觉痛,并發(fā)性較高役衡;維持鎖狀態(tài)的成本較大;
    • 頁級鎖(早些時候支持)
  • 所策略: 在鎖粒度及數(shù)據(jù)安全性之間尋求一種平衡機制薪棒;

    • 存儲引擎:每種存儲引擎都可以自行實現(xiàn)其所策略和鎖粒度
    • MySQL Server:表級別手蝎,可自行決定,也允許顯示請求俐芯;
  • 根據(jù)所本身根據(jù)用戶手動施加還是由服務(wù)器自動實現(xiàn)柑船,鎖又可以分兩種類型:

    • 顯式鎖:用火狐手動請求施加的鎖

    • 隱式鎖:有存儲引擎(或mysql服務(wù)器)自行根據(jù)需要施加的鎖;

      顯示鎖使用:
      (1) LOCK TABLES 命令:鎖定整張表或多張表
      用法:LOCK TABLES tbl_name [[AS] alias] lock_type [,tbl_name [[AS] alias ] lock_type] ...
      lock_type : 所類型 READ[ LOCAL] | [LOW_PRIORITY] WRITE
      tbl_name: 鎖名稱

            UNLOCK TABLES; 解鎖泼各;
            
            (2) FLUSH TABLES 命令:作用在于如果一張表被打開了鞍时,需要把內(nèi)存中的所有數(shù)據(jù)都清到磁盤上,在把表關(guān)閉扣蜻;
            用法:FLUSH TABLES tbl_name[,...] [WITH READ LOCK] [FOR UPDATE]
                
                WITH READ LOCK: 施加讀鎖
                FOR UPDATE: 請求修改逆巍,即施加寫鎖
      
            (3) SELECT 語句:鎖定表中的某些行
                
                用法:SELECT clause [FOR UPDATE] [WITH READ LOCK]
      

示例:
    MariaDB [(none)]> CREATE DATABASE testdb; #創(chuàng)建數(shù)據(jù)庫
    Query OK, 1 row affected (0.01 sec)
    
    MariaDB [(none)]> USE testdb
    Database changed
    MariaDB [testdb]> CREATE TABLE tbl;  #創(chuàng)建表
    ERROR 1113 (42000): A table must have at least 1 column
    MariaDB [testdb]> CREATE TABLE tbl (id INT NOT NULL ,name VARCHAR(50));  #插入數(shù)據(jù)
    Query OK, 0 rows affected (0.05 sec)
    
    MariaDB [testdb]> INSERT INTO tbl (id,name) VALUE (1,'TOM');
    Query OK, 1 row affected (0.01 sec)
    
    MariaDB [testdb]> SELECT * FROM tbl; 
    +----+------+
    | id | name |
    +----+------+
    |  1 | TOM  |
    +----+------+
    1 row in set (0.01 sec)
    
    MariaDB [testdb]> LOCK TABLE tbl READ; #施加讀鎖
    Query OK, 0 rows affected (0.00 sec)

    另外啟動一個線程:
    MariaDB [(none)]> use testdb;
    Reading table information for completion of table and column names
    You can turn off this feature to get a quicker startup with -A
    
    Database changed
    MariaDB [testdb]> SELECT * FROM tbl;  
    +----+------+
    | id | name |
    +----+------+
    |  1 | TOM  |
    +----+------+
    1 row in set (0.00 sec)
    
    MariaDB [testdb]> INSERT INTO tbl (id,name) VALUE (2,‘JERRY’);  #插入數(shù)據(jù)被阻塞
    
    線程1釋放鎖:
    MariaDB [testdb]> UNLOCK TABLES;
    Query OK, 0 rows affected (0.00 sec)
    線程2插入數(shù)據(jù)成功:
    MariaDB [testdb]> INSERT INTO tbl (id,name) VALUE (2,'JERRY');
    Query OK, 1 row affected (0.01 sec)
事務(wù)日志:

事務(wù)日志就是mysql數(shù)據(jù)文件之外的另外一個存儲區(qū)域,這個存儲區(qū)域帶來的作用是:當一個事務(wù)型存儲引擎在運行過程中莽使,需要啟動一個事務(wù)并完成數(shù)據(jù)修改時锐极,所有的修改操作(由多個sql語句組成),每一次的操作所涉及到的數(shù)據(jù)修改芳肌,這個修改的操作要轉(zhuǎn)換成底層存儲引擎所支持的相關(guān)操作的操作過程灵再,它會把每一次的sql語句所涉及的操作步驟,具體的過程記錄在事務(wù)日志文件中亿笤。
注意翎迁,事務(wù)日志記錄的是每一步的具體操作;例如净薛,插入一行的數(shù)據(jù)是什么汪榔、插入什么位置、什么時候插入得等都記錄下來肃拜;再例如痴腌,如果是修改幾行,先修改哪行后修改哪行燃领、幾點開始修改士聪、幾點結(jié)束等等都記錄下來;而且這個日志要能夠重現(xiàn)操作就叫做事務(wù)日志猛蔽。
一個事務(wù)型存儲引擎它的操作借助于事務(wù)日志來保證其對應(yīng)的事務(wù)特性剥悟;所以,任何事務(wù)型存儲引擎的相關(guān)操作,默認不會直接寫在數(shù)據(jù)庫文件上懦胞,而是先寫在事務(wù)日志中,并且事務(wù)日志為保證足夠可靠凉泄,基本上很少在內(nèi)存中緩沖躏尉,寫完建基本比較差,都會先寫在內(nèi)存上后众,然后等過一會再同步到磁盤上胀糜;事務(wù)日志也有這段緩沖區(qū),但這個緩沖區(qū)不能太大時間也不能太久蒂誉,因為如果允許緩存5秒鐘教藻,系統(tǒng)崩潰最大會丟失5秒的數(shù)據(jù),所以建議這個時間要足夠短右锨,一般為1秒鐘同步到磁盤上一次括堤;但是,同步越頻繁性能就越差绍移,數(shù)據(jù)可靠性就越高悄窃。
事務(wù)日志的每一步在記錄時,還會把修改之前的原始數(shù)據(jù)內(nèi)容也記錄下來蹂窖,這是為了支持undo和redo機制而記錄的轧抗;即當記錄的是修改數(shù)據(jù)時會把又該的數(shù)據(jù)之前的數(shù)據(jù)記錄下來。假如瞬测,操作進行到一半服務(wù)器崩潰了横媚,把修改的操作日志撤銷了即可,因為還沒有同步到磁盤上月趟;如為例如保證數(shù)據(jù)的穩(wěn)定性灯蝴,一個大事務(wù)中間有可能事務(wù)還沒完成,已經(jīng)在事務(wù)日志記錄了30個孝宗,再記錄事務(wù)日志會先把一部分信息往磁盤上同步绽乔,開始真正修改原始數(shù)據(jù)了,這時如果崩潰碳褒,則只能把已經(jīng)同步到表中的數(shù)據(jù)撤銷折砸,這就是undo機制;
還有一種情況是沙峻,比如一個事務(wù)有60個sql語句都寫完了且都記錄在事務(wù)日志中了睦授,但只有氣筒30個同步到了磁盤上,如果此時崩潰摔寨,則此時數(shù)據(jù)是不一致的去枷;因為有些事務(wù)已經(jīng)提交,但是沒有存儲到磁盤上,這樣就必須把事務(wù)日志中為完成的語句同步到磁盤上删顶,這就是redo機制竖螃;
同步的要做提交,沒能完成的要做回滾逗余,這就是崩潰后恢復(fù)特咆。
如果日志文件非常大,恰好寫滿了崩潰录粱,下次啟動mysql時腻格,必須把里面的所有語句統(tǒng)統(tǒng)同步到磁盤才能正常啟動,啥繁;如果事務(wù)日志文件大道2G菜职,為了能夠把2G的語句同步到磁盤上,有可能mysql服務(wù)器啟動半小時旗闽,所以為了避免崩潰后啟動時間太長酬核,把日志文件設(shè)置小一點;但是适室,有事會出現(xiàn)日志填滿了愁茁,但是日志內(nèi)容還沒來的急同步到磁盤上,還有新的日志需要寫進來亭病,那么久在啟動一個文件鹅很;也就是說日志文件一般啟動2個或3個是輪轉(zhuǎn)使用的,所謂輪轉(zhuǎn)指的是第一個日志文件填滿了就用第二個罪帖,同時把第一個日志文件同步到磁盤上促煮,等第二個日志寫滿了就可以再使用第一個了,這樣輪轉(zhuǎn)使用整袁,由多個事務(wù)日志文件組成的叫做事務(wù)日志組菠齿,日志組內(nèi)至少應(yīng)該有2個文件,但是多了同樣不好坐昙。
事務(wù)日志文件和數(shù)據(jù)文件不應(yīng)該放在同一磁盤上绳匀,因為會對磁盤寫IO操作帶來很大壓力,影響其性能炸客;分開存放比較理想疾棵,但是有些場景又要必須放在一起,例如基于邏輯卷操作時痹仙;
如果事務(wù)日志所在磁盤崩潰是尔,則數(shù)據(jù)庫數(shù)據(jù)無法保持一致;所以开仰,要把事務(wù)日志磁盤做鏡像拟枚;建議使用raid1薪铜;數(shù)據(jù)文件也很重要建議使用raid10;

  • 事務(wù):一組原子性的SQL查詢恩溅,或者多個SQL語句組成了一個獨立的工作單元
    • 事務(wù)日志:將隨機寫轉(zhuǎn)換為順序?qū)?br> innodb_log_files_in_group:一個日志組內(nèi)有多少個日志文件隔箍,默認2個;
      innodb_log_group_home_dir:日志組目錄路徑脚乡,當前目錄就是datadir指定的路徑
      innodb_log_file_size:每一個InnoDB事務(wù)日志的大小蜒滩,默認5M
      innodb_mirrored_log_groups
      修改配置文件,重啟生效每窖;這些參數(shù)帮掉,建議在mysql初始化時就要設(shè)置好再啟動弦悉,而不能在啟動后再修改參數(shù)是不理想的做法窒典;
  • ACID測試:從四個角度判斷存儲引擎是否支持事務(wù)
    • A:automicity,原子性稽莉;整個事務(wù)中的所有操作要么全部成功執(zhí)行瀑志,要么全部失敗后回滾;
    • C:consistency污秆,一致性劈猪;數(shù)據(jù)庫總是從一個一致性狀態(tài)轉(zhuǎn)換為另一個一致性狀態(tài);
    • I:isolation良拼,隔離性战得;一個事務(wù)所做出的操作在提交之前,是不能為其它事務(wù)所見的庸推,隔離有多種級別常侦,主要是為了并發(fā),隔離級別一個有4個贬媒;
    • D:durability聋亡,持久性;事務(wù)一旦提交际乘,其所做的修改就會永久保存于數(shù)據(jù)庫中坡倔;

注意:MyISAM存儲引擎是不支持事務(wù)的,InnoDB支持事務(wù)脖含,所以要想使用事務(wù)得確保使用的是InnoDB等支持事務(wù)的存儲引擎罪塔;

  • mysql默認把每個語句當做一個事務(wù)提交,可以手動關(guān)閉自動提交功能养葵,手動來啟動事務(wù)垢袱;

      啟動事務(wù):START TRANSACTION
      結(jié)束事務(wù):
          (1)完成,提交:COMMIT
          (2)未完成港柜,回滾:ROLLBACK
              回滾時如果做過時間點保存可以一點點回滾请契;
              事務(wù)支持savepoint
                  SAVEPINIT identifier咳榜;設(shè)置保存點
                  ROLLBACK TO [SAVEPOINT] identifier;回滾到指定保存點爽锥,默認回滾到最開始處
                  RELEASE SAVEPOINT identifier涌韩;釋放保存點
    

示例:
     查看是否開啟自動提交:
     MariaDB [(none)]> SHOW GLOBAL VARIABLES LIKE '%commit%';
    +-------------------------------------------+-------+
    | Variable_name                             | Value |
    +-------------------------------------------+-------+
    | aria_group_commit                         | none  |
    | aria_group_commit_interval                | 0     |
    | autocommit                                | ON    |
    | innodb_commit_concurrency                 | 0     |
    | innodb_flush_log_at_trx_commit            | 1     |
    | innodb_use_global_flush_log_at_trx_commit | ON    |
    +-------------------------------------------+-------+

    autocommit=ON:自動提交,把每一個執(zhí)行的語句當做一個事務(wù)氯夷,執(zhí)行語句就提交臣樱,因為每一次事務(wù)提交都會導(dǎo)致數(shù)據(jù)要從事務(wù)日志緩沖區(qū)寫到事務(wù)日志,隨后還要從事務(wù)日志寫到數(shù)據(jù)文件腮考;這很可能會影響性能雇毫,而且很多時候多個語句才是一個事務(wù);
    因此可以使用set修改變量踩蔚,關(guān)閉自動提交功能棚放;
    MariaDB [(none)]> SET @@SESSION.autocommit=OFF;  #修改session級別的參數(shù),關(guān)閉自動提交
    Query OK, 0 rows affected (0.00 sec)
    MariaDB [(none)]> SHOW VARIABLES LIKE 'autocommit';
    +---------------+-------+
    | Variable_name | Value |
    +---------------+-------+
    | autocommit    | OFF   |
    +---------------+-------+

    示例:
        手動啟動事務(wù):
        MariaDB [(none)]> START TRANSACTION;
        MariaDB [(none)]> use testdb;   
        
        Database changed
        MariaDB [testdb]> SELECT * FROM tbl;
        +----+-------+
        | id | name  |
        +----+-------+
        |  1 | TOM   |
        |  2 | JERRY |
        +----+-------+
        2 rows in set (0.00 sec)
        
        MariaDB [testdb]> INSERT INTO tbl (id,name) VALUE (3,'LUCY');
        Query OK, 1 row affected (0.01 sec)
        
        MariaDB [testdb]> UPDATE tbl SET name='guojing' WHERE id=1;
        Query OK, 1 row affected (0.00 sec)
        Rows matched: 1  Changed: 1  Warnings: 0
        
        MariaDB [testdb]> SELECT * FROM tbl;
        +----+---------+
        | id | name    |
        +----+---------+
        |  1 | guojing |
        |  2 | JERRY   |
        |  3 | LUCY    |
        +----+---------+
        3 rows in set (0.00 sec)
        
        MariaDB [testdb]> ROLLBACK; #手動回滾馅闽,結(jié)束事務(wù)
        Query OK, 0 rows affected (0.01 sec)
        
        MariaDB [testdb]> SELECT * FROM tbl;
        +----+-------+
        | id | name  |
        +----+-------+
        |  1 | TOM   |
        |  2 | JERRY |
        +----+-------+
        2 rows in set (0.00 sec)

    示例2:
        MariaDB [testdb]> START TRANSACTION;
        Query OK, 0 rows affected (0.00 sec)
        
        MariaDB [testdb]> INSERT INTO tbl VALUE (3,'LUCK'),(4,'MURNN');
        Query OK, 2 rows affected (0.02 sec)
        Records: 2  Duplicates: 0  Warnings: 0
        
        MariaDB [testdb]> SELECT * FROM tbl;
        +----+-------+
        | id | name  |
        +----+-------+
        |  1 | TOM   |
        |  2 | JERRY |
        |  3 | LUCK  |
        |  4 | MURNN |
        +----+-------+
        4 rows in set (0.00 sec)
        
        MariaDB [testdb]> SAVEPOINT first;   #做時間點飘蚯,名稱為first
        Query OK, 0 rows affected (0.00 sec)
        
        MariaDB [testdb]> UPDATE tbl SET name='guojing' WHERE id=1;
        Query OK, 1 row affected (0.00 sec)
        Rows matched: 1  Changed: 1  Warnings: 0
        
        MariaDB [testdb]> SAVEPOINT second;  #做第二個時間保存點,名稱為second
        Query OK, 0 rows affected (0.00 sec)            
        
        MariaDB [testdb]> INSERT INTO tbl VALUE (5,'HAHA');
        Query OK, 1 row affected (0.00 sec)
        
        MariaDB [testdb]> SELECT * FROM tbl;
        +----+---------+
        | id | name    |
        +----+---------+
        |  1 | guojing |
        |  2 | JERRY   |
        |  3 | LUCK    |
        |  4 | MURNN   |
        |  5 | HAHA    |
        +----+---------+
        5 rows in set (0.00 sec)

        MariaDB [testdb]> ROLLBACK TO second;  #回滾到第二個保存點
        Query OK, 0 rows affected (0.00 sec)
        
        MariaDB [testdb]> SELECT * FROM tbl;
        +----+---------+
        | id | name    |
        +----+---------+
        |  1 | guojing |
        |  2 | JERRY   |
        |  3 | LUCK    |
        |  4 | MURNN   |
        +----+---------+
        4 rows in set (0.00 sec)
        
        MariaDB [testdb]> ROLLBACK TO first;  #回滾到第一個保存點
        Query OK, 0 rows affected (0.00 sec)
        
        MariaDB [testdb]> SELECT * FROM tbl;
        +----+-------+
        | id | name  |
        +----+-------+
        |  1 | TOM   |
        |  2 | JERRY |
        |  3 | LUCK  |
        |  4 | MURNN |
        +----+-------+
        4 rows in set (0.00 sec)
        
        MariaDB [testdb]> COMMIT; 手動提交福也,結(jié)束事務(wù)
        Query OK, 0 rows affected (0.01 sec)

建議:手動顯示請求和提交事務(wù)局骤,不要使用自動提交功能

事務(wù)的隔離級別:

由低到高,分為4個級別:

  • 第一級別:read-uncommitted;讀未提交--> 會存在臟讀;
    看到數(shù)據(jù)可能是未提交的度帮,別人回滾后傻工,看到的數(shù)據(jù)不準確;

  • 第二級別:read-committed;讀提交--> 會產(chǎn)生不可重復(fù)讀;
    只有別人提交后才能看到數(shù)據(jù),解決了臟讀泣洞;
    不可重復(fù)讀,指的是同一事務(wù)中兩次讀取同一數(shù)據(jù)得到內(nèi)容不一樣默色;就是別人沒提交時讀到的內(nèi)容球凰,別人修改數(shù)據(jù)提交后又讀到的,兩次讀取的結(jié)果不同腿宰;這就叫不可重復(fù)讀呕诉;

  • 第三級別:repeatable-read;可重讀--> 會產(chǎn)生幻讀吃度;默認級別;
    兩次讀取數(shù)據(jù)甩挫,只要自己沒提交,不管別人提沒提交椿每,自己做一快照伊者,如果啟動事務(wù)時有三行數(shù)據(jù)英遭,讀的過程中只要自己不提交只有三行數(shù)據(jù),但是亦渗,外衣別的事務(wù)提交了數(shù)據(jù)挖诸,例如新增了幾個行,那幾行明明在法精,但自己假裝看不見多律,產(chǎn)生幻讀;

  • 第四級別:serializable搂蜓;可串行化--> 性能較差狼荞;
    如果別人沒提交,讀的數(shù)據(jù)是別人沒提交的帮碰,要等待別人的事務(wù)完成才能讀取到相味,有先有后,避免了幻讀收毫;

          查看默認事務(wù)隔離級別:
          MariaDB [(none)]> SHOW GLOBAL VARIABLES LIKE '%tx%';  
          +---------------+-----------------+
          | Variable_name | Value           |
          +---------------+-----------------+
          | tx_isolation  | REPEATABLE-READ |
          +---------------+-----------------+
          設(shè)置隔離級別:
          MariaDB [(none)]> SET @@global.tx_isolation='READ-COMMITTED';  
          Query OK, 0 rows affected (0.00 sec)            
          MariaDB [(none)]> SHOW GLOBAL VARIABLES LIKE '%tx%';
          +---------------+----------------+
          | Variable_name | Value          |
          +---------------+----------------+
          | tx_isolation  | READ-COMMITTED |
          +---------------+----------------+
          1 row in set (0.00 sec) 
          
           查看InnoDB存儲引擎的狀態(tài)信息:
           MariaDB [testdb]> SHOW ENGINE innodb STATUS\G;
    

MySQL是通過MVCC機制來實現(xiàn)事務(wù)隔離級別控制的攻走;為什么啟動2個事務(wù)殷勘,基于PREPEATABLE-READ 隔離級別修改數(shù)據(jù)但還能看到之前的數(shù)據(jù)此再,就是因為自己啟動了一個快照,而快照功能的創(chuàng)建玲销,刪除等等都是由事務(wù)功能mysql服務(wù)器自動在服務(wù)器級別進行管理的

    示例:兩個線程输拇,分別驗證各個事務(wù)隔離級別的效果
    (1)演示讀未提交,兩個線程控制臺均設(shè)置事務(wù)隔離級別為讀未提交,并關(guān)閉事務(wù)自動提交功能     
    MariaDB [testdb]> SET @@SESSION.tx_isolation='READ-UNCOMMITTED';
    Query OK, 0 rows affected (0.00 sec)
    
    MariaDB [(none)]> SET @@SESSION.autocommit=OFF;
    Query OK, 0 rows affected (0.00 sec)
    
    兩邊同時啟動事務(wù):
    MariaDB [(none)]> START TRANSACTION;
    
    線程1查看:
    MariaDB [testdb]> SELECT * FROM tbl;
    +----+-------+
    | id | name  |
    +----+-------+
    |  1 | TOM   |
    |  2 | JERRY |
    |  3 | LUCK  |
    |  4 | MURNN |
    +----+-------+
    4 rows in set (0.00 sec)
    
    線程2插入數(shù)據(jù):
    MariaDB [testdb]> INSERT INTO tbl VALUE (5,'haha');
    Query OK, 1 row affected (0.00 sec)
    
    線程1再查看:
    MariaDB [testdb]> SELECT * FROM tbl;
    +----+-------+
    | id | name  |
    +----+-------+
    |  1 | TOM   |
    |  2 | JERRY |
    |  3 | LUCK  |
    |  4 | MURNN |
    |  5 | haha  |
    +----+-------+
    5 rows in set (0.00 sec)
    
    線程2:回滾贤斜,結(jié)束事務(wù):
    MariaDB [testdb]> ROLLBACK;
    Query OK, 0 rows affected (0.01 sec)
    
    線程1再查看:
    MariaDB [testdb]> SELECT * FROM tbl;
    +----+-------+
    | id | name  |
    +----+-------+
    |  1 | TOM   |
    |  2 | JERRY |
    |  3 | LUCK  |
    |  4 | MURNN |
    +----+-------+
    4 rows in set (0.00 sec)
    MariaDB [testdb]> COMMIT;   #提交結(jié)束事務(wù)
    Query OK, 0 rows affected (0.00 sec)

示例:演示讀提交
    兩個線程都改為讀提交策吠,并啟動事務(wù):
    MariaDB [testdb]> SET @@SESSION.tx_isolation='READ-COMMITTED';
    MariaDB [testdb]> START TRANSACTION;
    
    線程1啟動查詢:
    MariaDB [testdb]> SELECT * FROM tbl;
    +----+-------+
    | id | name  |
    +----+-------+
    |  1 | TOM   |
    |  2 | JERRY |
    |  3 | LUCK  |
    |  4 | MURNN |
    +----+-------+
    4 rows in set (0.01 sec)
    
    線程2插入數(shù)據(jù)未提交:
    MariaDB [testdb]> INSERT INTO tbl VALUE (5,'haha');
    Query OK, 1 row affected (0.02 sec)
    
    線程1再查看數(shù)據(jù)未變化:
    MariaDB [testdb]> SELECT * FROM tbl;
    +----+-------+
    | id | name  |
    +----+-------+
    |  1 | TOM   |
    |  2 | JERRY |
    |  3 | LUCK  |
    |  4 | MURNN |
    +----+-------+
    4 rows in set (0.00 sec)
    
    線程2提交事務(wù):
    MariaDB [testdb]> COMMIT;
    Query OK, 0 rows affected (0.02 sec)
    
    線程1再查看,數(shù)據(jù)發(fā)生變化
    MariaDB [testdb]> SELECT * FROM tbl;
    +----+-------+
    | id | name  |
    +----+-------+
    |  1 | TOM   |
    |  2 | JERRY |
    |  3 | LUCK  |
    |  4 | MURNN |
    |  5 | haha  |
    +----+-------+
    5 rows in set (0.00 sec)
    MariaDB [testdb]> COMMIT;  #提交事務(wù)

示例:演示幻讀瘩绒,可重復(fù)讀
    兩個線程都修改事務(wù)級別為可重復(fù)讀猴抹,并啟動事務(wù):
    mysql> SHOW GLOBAL VARIABLES LIKE '%iso%';
    +-----------------------+-----------------+
    | Variable_name         | Value           |
    +-----------------------+-----------------+
    | transaction_isolation | REPEATABLE-READ |
    +-----------------------+-----------------+
    1 row in set (0.00 sec)
    mysql> SET @@SESSION.autocommit=OFF;
    Query OK, 0 rows affected (0.02 sec)
    
    線程1查看:
    mysql> SELECT * FROM tbl;
    +----+-------+
    | id | name  |
    +----+-------+
    |  1 | TOM   |
    |  2 | JERRY |
    |  3 | LUCK  |
    |  4 | HAHA  |
    +----+-------+
    4 rows in set (0.00 sec)
    
    線程2刪除1行(未提交):
    mysql> DELETE FROM tbl WHERE id=2;
    Query OK, 1 row affected (0.01 sec)
    
    mysql> SELECT * FROM tbl;
    +----+------+
    | id | name |
    +----+------+
    |  1 | TOM  |
    |  3 | LUCK |
    |  4 | HAHA |
    +----+------+
    3 rows in set (0.00 sec)
    
    線程1查看,未發(fā)生變化:
    mysql> SELECT * FROM tbl;
    +----+-------+
    | id | name  |
    +----+-------+
    |  1 | TOM   |
    |  2 | JERRY |
    |  3 | LUCK  |
    |  4 | HAHA  |
    +----+-------+
    4 rows in set (0.00 sec)
    
    線程2提交:
    mysql> COMMIT;
    Query OK, 0 rows affected (0.07 sec)
    
    線程1再查看锁荔,扔然未變化:
    mysql> SELECT * FROM tbl;
    +----+-------+
    | id | name  |
    +----+-------+
    |  1 | TOM   |
    |  2 | JERRY |
    |  3 | LUCK  |
    |  4 | HAHA  |
    +----+-------+
    4 rows in set (0.00 sec)
    
    線程1提交事務(wù)后再查看數(shù)據(jù)發(fā)生變化:
    mysql> COMMIT;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT * FROM tbl;
    +----+------+
    | id | name |
    +----+------+
    |  1 | TOM  |
    |  3 | LUCK |
    |  4 | HAHA |
    +----+------+
    3 rows in set (0.00 sec)

示例:演示可串行化
    2個線程都設(shè)置事務(wù)隔離級別可串行化:
    mysql> SET @@SESSION.transaction_isolation='SERIALIZABLE';
    線程1查看:
    mysql> SELECT * FROM tbl;
    +----+-------+
    | id | name  |
    +----+-------+
    |  1 | TOM   |
    |  3 | LUCK  |
    |  4 | HAHA  |
    |  2 | JERRY |
    +----+-------+
    4 rows in set (0.00 sec)
    
    線程2啟動事務(wù)蟀给,并插入數(shù)據(jù):
    mysql> START TRANSACTION;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> INSERT INTO tbl VALUE (5,'HUANG RONG');
    Query OK, 1 row affected (18.31 sec)
    
    線程1啟動事務(wù)并查看,被阻塞:
    mysql> START TRANSACTION;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT * FROM tbl;
    線程2提交事務(wù):
    mysql> COMMIT;
    Query OK, 0 rows affected (0.03 sec)
    
    線程1查看:
    mysql> SELECT * FROM tbl;
    ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
    mysql> SELECT * FROM tbl;
    +----+------------+
    | id | name       |
    +----+------------+
    |  1 | TOM        |
    |  3 | LUCK       |
    |  4 | HAHA       |
    |  2 | JERRY      |
    |  5 | HUANG RONG |
    +----+------------+
    5 rows in set (0.00 sec)
    mysql> commit;
    Query OK, 0 rows affected (0.00 sec)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末阳堕,一起剝皮案震驚了整個濱河市跋理,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌恬总,老刑警劉巖前普,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異壹堰,居然都是意外死亡拭卿,警方通過查閱死者的電腦和手機骡湖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來峻厚,“玉大人勺鸦,你說我怎么就攤上這事∧磕荆” “怎么了换途?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長刽射。 經(jīng)常有香客問我军拟,道長,這世上最難降的妖魔是什么誓禁? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任懈息,我火速辦了婚禮,結(jié)果婚禮上摹恰,老公的妹妹穿的比我還像新娘辫继。我一直安慰自己,他們只是感情好俗慈,可當我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布姑宽。 她就那樣靜靜地躺著,像睡著了一般闺阱。 火紅的嫁衣襯著肌膚如雪炮车。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天酣溃,我揣著相機與錄音瘦穆,去河邊找鬼。 笑死赊豌,一個胖子當著我的面吹牛扛或,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播碘饼,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼熙兔,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了派昧?” 一聲冷哼從身側(cè)響起黔姜,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蒂萎,沒想到半個月后秆吵,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡五慈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年纳寂,在試婚紗的時候發(fā)現(xiàn)自己被綠了主穗。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡毙芜,死狀恐怖忽媒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情腋粥,我是刑警寧澤晦雨,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站隘冲,受9級特大地震影響闹瞧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜展辞,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一奥邮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧罗珍,春花似錦洽腺、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至通殃,卻和暖如春度液,著一層夾襖步出監(jiān)牢的瞬間厕宗,已是汗流浹背画舌。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留已慢,地道東北人曲聂。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像佑惠,于是被迫代替她去往敵國和親朋腋。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容