面試高概率問題之事物管理

這幾天找工作,面試了將近10家公司赤拒,其中有幾個問題幾乎每家公司都會問,spring的事物機制應(yīng)該算是其中最常被問到的問題诱鞠,而且這個問題你回答的好挎挖,面試官會覺得你基本功很扎實,印象直接提升一個檔次航夺。今天就來詳細分析講解一下spring的事物機制蕉朵。文章有點長,看完保證你受益匪淺阳掐。

對了始衅,先來個花絮,有一天面試被問ACID是什么缭保,當(dāng)時想臥槽汛闸,這時啥,根本不知道艺骂。后來百度了才知道他是啥

原子性(Atomicity)部蛇,一致性(Consistency)筐乳,隔離性(Isolation),持久性(Durability)

原來就是這個,瞬間石化崇败,這么簡單地問題逮矛。

好辐马,進入正題访惜,先來一張圖

spring之事物管理

Spring并不直接管理事務(wù),而是提供了多種事務(wù)管理器宙址,他們將事務(wù)管理的職責(zé)委托給Hibernate或者JTA等持久化機制所提供的相關(guān)平臺框架的事務(wù)來實現(xiàn)轴脐。
Spring事務(wù)管理器的接口是org.springframework.transaction.PlatformTransactionManager,通過這個接口抡砂,Spring為各個平臺如JDBC大咱、Hibernate等都提供了對應(yīng)的事務(wù)管理器,但是具體的實現(xiàn)就是各個平臺自己的事情了注益。此接口的內(nèi)容如下:

package org.springframework.transaction;

public interface PlatformTransactionManager {

    //根據(jù)TransactionDefinition得到TransactionStatus 
    TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
   //根據(jù)TransactionDefinition得到TransactionStatus 
    void commit(TransactionStatus status) throws TransactionException;
   //根據(jù)TransactionDefinition得到TransactionStatus 
    void rollback(TransactionStatus status) throws TransactionException;
}

可以看到碴巾,spring是提供了3個基本的方法,然后讓各自jdbc框架自己去實現(xiàn)丑搔,所以Spring事務(wù)管理的一個優(yōu)點就是為不同的事務(wù)API提供一致的編程模型厦瓢,如JTA提揍、JDBC、Hibernate煮仇、JPA劳跃。

例如,我使用的是JDBC的事物管理

JDBC事物

當(dāng)然如果你使用Hibernate浙垫,也可以使用Hibernate的事物管理
org.springframework.orm.hibernate3.HibernateTransactionManager

#######事物的基本屬性
在上的PlatformTransactionManager 接口中有一個方法是

TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;

通過TransactionDefinition 來獲取事物的狀態(tài)刨仑,其中TransactionDefinition 就保存了事物的基本屬性。
下面我們來看看這個接口中的代碼

package org.springframework.transaction;

import java.sql.Connection;

public interface TransactionDefinition {
    int PROPAGATION_REQUIRED = 0;
    int PROPAGATION_SUPPORTS = 1;
    int PROPAGATION_MANDATORY = 2;
    int PROPAGATION_REQUIRES_NEW = 3;
    int PROPAGATION_NOT_SUPPORTED = 4;
    int PROPAGATION_NEVER = 5;
    int PROPAGATION_NESTED = 6;
    int ISOLATION_DEFAULT = -1;

    int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
    int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
    int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
    int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;

    int TIMEOUT_DEFAULT = -1;
    //獲取事務(wù)的傳播行為
    int getPropagationBehavior();
    //獲取事務(wù)的隔離級別
    int getIsolationLevel();
    //獲取事務(wù)的超時時間
    int getTimeout();
    //獲取事務(wù)是否只讀
    boolean isReadOnly();
    //獲取事務(wù)的傳播行為
    String getName();

上面被我注釋的4個方法夹姥,分別代表了事物的4基本基本屬性杉武,分別是,“傳播行為”辙售、“隔離級別”轻抱、“超時時間”、“只讀”旦部,其實還有第五個屬性祈搜,是“回滾規(guī)則”,這個一會會說到志鹃。

下面我們逐個分析

事務(wù)的傳播行為

事務(wù)的傳播行為是指當(dāng)事務(wù)方法被另一個事務(wù)方法調(diào)用時夭问,必須指定事務(wù)應(yīng)該如何傳播泽西。例如:方法可能繼續(xù)在現(xiàn)有事務(wù)中運行曹铃,也可能開啟一個新事務(wù),并在自己的事務(wù)中運行捧杉。Spring定義了七種傳播行為:

(1)PROPAGATION_REQUIRED:

表示當(dāng)前方法必須運行在事務(wù)中陕见。如果當(dāng)前事務(wù)存在,方法將會在該事務(wù)中運行味抖。否則评甜,會啟動一個新的事務(wù)
注:以下具體講解傳播行為的內(nèi)容參考自Spring事務(wù)機制詳解

//事務(wù)屬性 PROPAGATION_REQUIRED
methodA{
    ……
    methodB();
    ……
}

//事務(wù)屬性 PROPAGATION_REQUIRED
methodB{
   ……
}

單獨調(diào)用methodB方法:

main{ 
    metodB(); 
}  

相當(dāng)于

Main{ 
    Connection con=null; 
    try{ 
        con = getConnection(); 
        con.setAutoCommit(false); 

        //方法調(diào)用
        methodB(); 

        //提交事務(wù)
        con.commit(); 
    } Catch(RuntimeException ex) { 
        //回滾事務(wù)
        con.rollback();   
    } finally { 
        //釋放資源
        closeCon(); 
    } 
} 

Spring保證在methodB方法中所有的調(diào)用都獲得到一個相同的連接。在調(diào)用methodB時仔涩,沒有一個存在的事務(wù)忍坷,所以獲得一個新的連接,開啟了一個新的事務(wù)熔脂。
單獨調(diào)用MethodA時佩研,在MethodA內(nèi)又會調(diào)用MethodB.

執(zhí)行效果相當(dāng)于:

main{ 
    Connection con = null; 
    try{ 
        con = getConnection(); 
        methodA(); 
        con.commit(); 
    } catch(RuntimeException ex) { 
        con.rollback(); 
    } finally {    
        closeCon(); 
    }  
} 

調(diào)用MethodA時,環(huán)境中沒有事務(wù)霞揉,所以開啟一個新的事務(wù).當(dāng)在MethodA中調(diào)用MethodB時旬薯,環(huán)境中已經(jīng)有了一個事務(wù),所以methodB就加入當(dāng)前事務(wù)适秩。

(2)PROPAGATION_SUPPORTS

如果存在一個事務(wù)绊序,支持當(dāng)前事務(wù)硕舆。如果沒有事務(wù),則非事務(wù)的執(zhí)行骤公。但是對于事務(wù)同步的事務(wù)管理器抚官,PROPAGATION_SUPPORTS與不使用事務(wù)有少許不同。

//事務(wù)屬性 PROPAGATION_REQUIRED
methodA(){
  methodB();
}

//事務(wù)屬性 PROPAGATION_SUPPORTS
methodB(){
  ……
}

單純的調(diào)用methodB時淋样,methodB方法是非事務(wù)的執(zhí)行的耗式。當(dāng)調(diào)用methdA時,methodB則加入了methodA的事務(wù)中,事務(wù)地執(zhí)行。

(3)PROPAGATION_MANDATORY

如果已經(jīng)存在一個事務(wù)趁猴,支持當(dāng)前事務(wù)刊咳。如果沒有一個活動的事務(wù),則拋出異常儡司。

//事務(wù)屬性 PROPAGATION_REQUIRED
methodA(){
    methodB();
}

//事務(wù)屬性 PROPAGATION_MANDATORY
    methodB(){
    ……
}

當(dāng)單獨調(diào)用methodB時娱挨,因為當(dāng)前沒有一個活動的事務(wù),則會拋出異常throw new IllegalTransactionStateException(“Transaction propagation ‘mandatory’ but no existing transaction found”);當(dāng)調(diào)用methodA時捕犬,methodB則加入到methodA的事務(wù)中跷坝,事務(wù)地執(zhí)行。

(4)PROPAGATION_REQUIRES_NEW

總是開啟一個新的事務(wù)碉碉。如果一個事務(wù)已經(jīng)存在柴钻,則將這個存在的事務(wù)掛起。

//事務(wù)屬性 PROPAGATION_REQUIRED
methodA(){
    doSomeThingA();
    methodB();
    doSomeThingB();
}

//事務(wù)屬性 PROPAGATION_REQUIRES_NEW
methodB(){
    ……
}

調(diào)用A方法:

main(){
    methodA();
}

相當(dāng)于

main(){
    TransactionManager tm = null;
    try{
        //獲得一個JTA事務(wù)管理器
        tm = getTransactionManager();
        tm.begin();//開啟一個新的事務(wù)
        Transaction ts1 = tm.getTransaction();
        doSomeThing();
        tm.suspend();//掛起當(dāng)前事務(wù)
        try{
            tm.begin();//重新開啟第二個事務(wù)
            Transaction ts2 = tm.getTransaction();
            methodB();
            ts2.commit();//提交第二個事務(wù)
        } Catch(RunTimeException ex) {
            ts2.rollback();//回滾第二個事務(wù)
        } finally {
            //釋放資源
        }
        //methodB執(zhí)行完后垢粮,恢復(fù)第一個事務(wù)
        tm.resume(ts1);
        doSomeThingB();
        ts1.commit();//提交第一個事務(wù)
    } catch(RunTimeException ex) {
        ts1.rollback();//回滾第一個事務(wù)
    } finally {
        //釋放資源
    }
}

在這里贴届,我把ts1稱為外層事務(wù),ts2稱為內(nèi)層事務(wù)蜡吧。從上面的代碼可以看出,ts2與ts1是兩個獨立的事務(wù)昔善,互不相干元潘。Ts2是否成功并不依賴于 ts1。如果methodA方法在調(diào)用methodB方法后的doSomeThingB方法失敗了君仆,而methodB方法所做的結(jié)果依然被提交翩概。而除了 methodB之外的其它代碼導(dǎo)致的結(jié)果卻被回滾了。使用PROPAGATION_REQUIRES_NEW,需要使用 JtaTransactionManager作為事務(wù)管理器返咱。

(5)PROPAGATION_NOT_SUPPORTED

總是非事務(wù)地執(zhí)行钥庇,并掛起任何存在的事務(wù)。使用PROPAGATION_NOT_SUPPORTED,也需要使用JtaTransactionManager作為事務(wù)管理器洛姑。(代碼示例同上上沐,可同理推出)

(6)PROPAGATION_NEVER

總是非事務(wù)地執(zhí)行,如果存在一個活動事務(wù)楞艾,則拋出異常参咙。

(7)PROPAGATION_NESTED

如果一個活動的事務(wù)存在龄广,則運行在一個嵌套的事務(wù)中. 如果沒有活動事務(wù), 則按TransactionDefinition.PROPAGATION_REQUIRED 屬性執(zhí)行。這是一個嵌套事務(wù),使用JDBC 3.0驅(qū)動時,僅僅支持DataSourceTransactionManager作為事務(wù)管理器蕴侧。需要JDBC 驅(qū)動的java.sql.Savepoint類择同。有一些JTA的事務(wù)管理器實現(xiàn)可能也提供了同樣的功能。使用PROPAGATION_NESTED净宵,還需要把PlatformTransactionManager的nestedTransactionAllowed屬性設(shè)為true;而 nestedTransactionAllowed屬性值默認為false敲才。

//事務(wù)屬性 PROPAGATION_REQUIRED
methodA(){
    doSomeThingA();
    methodB();
    doSomeThingB();
}

//事務(wù)屬性 PROPAGATION_NESTED
methodB(){
    ……
}

如果單獨調(diào)用methodB方法,則按REQUIRED屬性執(zhí)行择葡。如果調(diào)用methodA方法紧武,相當(dāng)于下面的效果:

main(){
    Connection con = null;
    Savepoint savepoint = null;
    try{
        con = getConnection();
        con.setAutoCommit(false);
        doSomeThingA();
        savepoint = con2.setSavepoint();
        try{
            methodB();
        } catch(RuntimeException ex) {
            con.rollback(savepoint);
        } finally {
            //釋放資源
        }
        doSomeThingB();
        con.commit();
    } catch(RuntimeException ex) {
        con.rollback();
    } finally {
        //釋放資源
    }
}

當(dāng)methodB方法調(diào)用之前,調(diào)用setSavepoint方法敏储,保存當(dāng)前的狀態(tài)到savepoint阻星。如果methodB方法調(diào)用失敗,則恢復(fù)到之前保存的狀態(tài)已添。但是需要注意的是妥箕,這時的事務(wù)并沒有進行提交,如果后續(xù)的代碼(doSomeThingB()方法)調(diào)用失敗更舞,則回滾包括methodB方法的所有操作畦幢。

嵌套事務(wù)一個非常重要的概念就是內(nèi)層事務(wù)依賴于外層事務(wù)。外層事務(wù)失敗時缆蝉,會回滾內(nèi)層事務(wù)所做的動作宇葱。而內(nèi)層事務(wù)操作失敗并不會引起外層事務(wù)的回滾。

隔離級別

事務(wù)的第二個維度就是隔離級別(isolation level)返奉。隔離級別定義了一個事務(wù)可能受其他并發(fā)事務(wù)影響的程度贝搁。
(1)并發(fā)事務(wù)引起的問題
在典型的應(yīng)用程序中吗氏,多個事務(wù)并發(fā)運行芽偏,經(jīng)常會操作相同的數(shù)據(jù)來完成各自的任務(wù)。并發(fā)雖然是必須的弦讽,但可能會導(dǎo)致一下的問題污尉。

臟讀(Dirty reads)——臟讀

發(fā)生在一個事務(wù)讀取了另一個事務(wù)改寫但尚未提交的數(shù)據(jù)時。如果改寫在稍后被回滾了往产,那么第一個事務(wù)獲取的數(shù)據(jù)就是無效的被碗。

不可重復(fù)讀(Nonrepeatable read)——不可重復(fù)讀

發(fā)生在一個事務(wù)執(zhí)行相同的查詢兩次或兩次以上,但是每次都得到不同的數(shù)據(jù)時仿村。這通常是因為另一個并發(fā)事務(wù)在兩次查詢期間進行了更新锐朴。

幻讀(Phantom read)——幻讀

與不可重復(fù)讀類似。它發(fā)生在一個事務(wù)(T1)讀取了幾行數(shù)據(jù)蔼囊,接著另一個并發(fā)事務(wù)(T2)插入了一些數(shù)據(jù)時焚志。在隨后的查詢中衣迷,第一個事務(wù)(T1)就會發(fā)現(xiàn)多了一些原本不存在的記錄。
不可重復(fù)讀與幻讀的區(qū)別

不可重復(fù)讀的重點是修改:
同樣的條件, 你讀取過的數(shù)據(jù), 再次讀取出來發(fā)現(xiàn)值不一樣了
例如:在事務(wù)1中酱酬,Mary 讀取了自己的工資為1000,操作并沒有完成

 con1 = getConnection();  
    select salary from employee empId ="Mary";  

在事務(wù)2中壶谒,這時財務(wù)人員修改了Mary的工資為2000,并提交了事務(wù).

 con2 = getConnection();  
    update employee set salary = 2000;  
    con2.commit();  

在事務(wù)1中,Mary 再次讀取自己的工資時膳沽,工資變?yōu)榱?000

   //con1  
    select salary from employee empId ="Mary"; 

在一個事務(wù)中前后兩次讀取的結(jié)果并不一致汗菜,導(dǎo)致了不可重復(fù)讀。

幻讀的重點在于新增或者刪除:
同樣的條件, 第1次和第2次讀出來的記錄數(shù)不一樣
例如:目前工資為1000的員工有10人挑社。事務(wù)1,讀取所有工資為1000的員工陨界。

 con1 = getConnection();  
    Select * from employee where salary =1000; 

共讀取10條記錄

這時另一個事務(wù)向employee表插入了一條員工記錄,工資也為1000

  con2 = getConnection();  
    Insert into employee(empId,salary) values("Lili",1000);  
    con2.commit();  

事務(wù)1再次讀取所有工資為1000的員工

   //con1  
    select * from employee where salary =1000;  

共讀取到了11條記錄痛阻,這就產(chǎn)生了幻像讀普碎。

從總的結(jié)果來看, 似乎不可重復(fù)讀和幻讀都表現(xiàn)為兩次讀取的結(jié)果不一致。但如果你從控制的角度來看, 兩者的區(qū)別就比較大录平。
對于前者, 只需要鎖住滿足條件的記錄麻车。
對于后者, 要鎖住滿足條件及其相近的記錄。

幾種隔離級別

ISOLATION_DEFAULT

使用后端數(shù)據(jù)庫默認的隔離級別

ISOLATION_READ_UNCOMMITTED

最低的隔離級別斗这,允許讀取尚未提交的數(shù)據(jù)變更动猬,可能會導(dǎo)致臟讀、幻讀或不可重復(fù)讀

ISOLATION_READ_COMMITTED

允許讀取并發(fā)事務(wù)已經(jīng)提交的數(shù)據(jù)表箭,可以阻止臟讀赁咙,但是幻讀或不可重復(fù)讀仍有可能發(fā)生

ISOLATION_REPEATABLE_READ

對同一字段的多次讀取結(jié)果都是一致的,除非數(shù)據(jù)是被本身事務(wù)自己所修改免钻,可以阻止臟讀和不可重復(fù)讀彼水,但幻讀仍有可能發(fā)生

ISOLATION_SERIALIZABLE

最高的隔離級別,完全服從ACID的隔離級別极舔,確保阻止臟讀凤覆、不可重復(fù)讀以及幻讀,也是最慢的事務(wù)隔離級別拆魏,因為它通常是通過完全鎖定事務(wù)相關(guān)的數(shù)據(jù)庫表來實現(xiàn)的

只讀

事務(wù)的第三個特性是它是否為只讀事務(wù)盯桦。如果事務(wù)只對后端的數(shù)據(jù)庫進行該操作,數(shù)據(jù)庫可以利用事務(wù)的只讀特性來進行一些特定的優(yōu)化渤刃。通過將事務(wù)設(shè)置為只讀拥峦,你就可以給數(shù)據(jù)庫一個機會,讓它應(yīng)用它認為合適的優(yōu)化措施卖子。

事務(wù)超時

為了使應(yīng)用程序很好地運行略号,事務(wù)不能運行太長的時間。因為事務(wù)可能涉及對后端數(shù)據(jù)庫的鎖定,所以長時間的事務(wù)會不必要的占用數(shù)據(jù)庫資源玄柠。事務(wù)超時就是事務(wù)的一個定時器氛琢,在特定時間內(nèi)事務(wù)如果沒有執(zhí)行完畢,那么就會自動回滾随闪,而不是一直等待其結(jié)束阳似。

回滾規(guī)則

事務(wù)五邊形的最后一個方面是一組規(guī)則,這些規(guī)則定義了哪些異常會導(dǎo)致事務(wù)回滾而哪些不會铐伴。默認情況下撮奏,事務(wù)只有遇到運行期異常時才會回滾,而在遇到檢查型異常時不會回滾(這一行為與EJB的回滾行為是一致的)
但是你可以聲明事務(wù)在遇到特定的檢查型異常時像遇到運行期異常那樣回滾当宴。同樣畜吊,你還可以聲明事務(wù)遇到特定的異常不回滾,即使這些異常是運行期異常户矢。

附帶小例子一個

    /**
     * 1.添加事務(wù)注解
     * 使用propagation 指定事務(wù)的傳播行為玲献,即當(dāng)前的事務(wù)方法被另外一個事務(wù)方法調(diào)用時如何使用事務(wù)。
     * 默認取值為REQUIRED梯浪,即使用調(diào)用方法的事務(wù)
     * REQUIRES_NEW:使用自己的事務(wù)捌年,調(diào)用的事務(wù)方法的事務(wù)被掛起。
     *
     * 2.使用isolation 指定事務(wù)的隔離級別挂洛,最常用的取值為READ_COMMITTED
     * 3.默認情況下 Spring 的聲明式事務(wù)對所有的運行時異常進行回滾礼预,也可以通過對應(yīng)的屬性進行設(shè)置。通常情況下虏劲,默認值即可托酸。
     * 4.使用readOnly 指定事務(wù)是否為只讀。 表示這個事務(wù)只讀取數(shù)據(jù)但不更新數(shù)據(jù)柒巫,這樣可以幫助數(shù)據(jù)庫引擎優(yōu)化事務(wù)励堡。若真的是一個只讀取數(shù)據(jù)庫值得方法,應(yīng)設(shè)置readOnly=true
     * 5.使用timeOut 指定強制回滾之前事務(wù)可以占用的時間堡掏。
     */
@Transactional(propagation=Propagation.REQUIRES_NEW,
            isolation=Isolation.READ_COMMITTED,
            noRollbackFor={UserAccountException.class},
            readOnly=true, timeout=3)
    @Override
    public void purchase(String username, String isbn) {
             //doSomething.....
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末应结,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子布疼,更是在濱河造成了極大的恐慌摊趾,老刑警劉巖币狠,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件游两,死亡現(xiàn)場離奇詭異,居然都是意外死亡漩绵,警方通過查閱死者的電腦和手機贱案,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人宝踪,你說我怎么就攤上這事侨糟。” “怎么了瘩燥?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵秕重,是天一觀的道長。 經(jīng)常有香客問我厉膀,道長溶耘,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任服鹅,我火速辦了婚禮凳兵,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘企软。我一直安慰自己庐扫,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布仗哨。 她就那樣靜靜地躺著形庭,像睡著了一般。 火紅的嫁衣襯著肌膚如雪厌漂。 梳的紋絲不亂的頭發(fā)上碘勉,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天,我揣著相機與錄音桩卵,去河邊找鬼验靡。 笑死,一個胖子當(dāng)著我的面吹牛雏节,可吹牛的內(nèi)容都是我干的胜嗓。 我是一名探鬼主播,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼钩乍,長吁一口氣:“原來是場噩夢啊……” “哼辞州!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起寥粹,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤变过,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后涝涤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體媚狰,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年阔拳,在試婚紗的時候發(fā)現(xiàn)自己被綠了崭孤。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,643評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖辨宠,靈堂內(nèi)的尸體忽然破棺而出遗锣,到底是詐尸還是另有隱情,我是刑警寧澤嗤形,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布精偿,位于F島的核電站,受9級特大地震影響赋兵,放射性物質(zhì)發(fā)生泄漏还最。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一毡惜、第九天 我趴在偏房一處隱蔽的房頂上張望拓轻。 院中可真熱鬧,春花似錦经伙、人聲如沸扶叉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽枣氧。三九已至,卻和暖如春垮刹,著一層夾襖步出監(jiān)牢的瞬間达吞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工荒典, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留酪劫,地道東北人。 一個月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓寺董,卻偏偏與公主長得像覆糟,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子遮咖,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,509評論 2 348

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