【JAVA】Spring事務管理詳解

事物的特性(ACID)

原子性: 事務是最小的執(zhí)行單位蚀苛,不允許分割令杈。事務的原子性確保動作要么全部完成,要么完全不起作用养葵;
一致性: 執(zhí)行事務前后入客,數(shù)據(jù)保持一致;
隔離性: 并發(fā)訪問數(shù)據(jù)庫時嚎莉,一個用戶的事物不被其他事物所干擾米酬,各并發(fā)事務之間數(shù)據(jù)庫是獨立的;
持久性: 一個事務被提交之后趋箩。它對數(shù)據(jù)庫中數(shù)據(jù)的改變是持久的赃额,即使數(shù)據(jù)庫發(fā)生故障也不應該對其有任何影響。

我們在使用JDBC或者Mybatis進行數(shù)據(jù)持久化操作時,我們的xml配置通常如下:

    <!-- 事務管理器 -->
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 數(shù)據(jù)源 -->
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!-- 開啟事務行為 -->
    <tx:annotation-driven transaction-manager="transactionManager" />

并發(fā)事務帶來的問題

在典型的應用程序中叫确,多個事務并發(fā)運行跳芳,經(jīng)常會操作相同的數(shù)據(jù)來完成各自的任務(多個用戶對統(tǒng)一數(shù)據(jù)進行操作)。并發(fā)雖然是必須的竹勉,但可能會導致一下的問題飞盆。

  • 臟讀(Dirty read): 當一個事務正在訪問數(shù)據(jù)并且對數(shù)據(jù)進行了修改,而這種修改還沒有提交到數(shù)據(jù)庫中次乓,這時另外一個事務也訪問了這個數(shù)據(jù)吓歇,然后使用了這個數(shù)據(jù)。因為這個數(shù)據(jù)是還沒有提交的數(shù)據(jù)票腰,那么另外一個事務讀到的這個數(shù)據(jù)是“臟數(shù)據(jù)”城看,依據(jù)“臟數(shù)據(jù)”所做的操作可能是不正確的。

  • 丟失修改(Lost to modify): 指在一個事務讀取一個數(shù)據(jù)時杏慰,另外一個事務也訪問了該數(shù)據(jù)测柠,那么在第一個事務中修改了這個數(shù)據(jù)后,第二個事務也修改了這個數(shù)據(jù)逃默。這樣第一個事務內(nèi)的修改結(jié)果就被丟失鹃愤,因此稱為丟失修改。
    例如:事務1讀取某表中的數(shù)據(jù)A=20完域,事務2也讀取A=20软吐,事務1修改A=A-1,事務2也修改A=A-1吟税,最終結(jié)果A=19凹耙,事務1的修改被丟失。

  • 不可重復讀(Unrepeatableread): 指在一個事務內(nèi)多次讀同一數(shù)據(jù)肠仪。在這個事務還沒有結(jié)束時肖抱,另一個事務也訪問該數(shù)據(jù)。那么异旧,在第一個事務中的兩次讀數(shù)據(jù)之間意述,由于第二個事務的修改導致第一個事務兩次讀取的數(shù)據(jù)可能不太一樣。這就發(fā)生了在一個事務內(nèi)兩次讀到的數(shù)據(jù)是不一樣的情況,因此稱為不可重復讀荤崇。

  • 幻讀(Phantom read): 幻讀與不可重復讀類似拌屏。它發(fā)生在一個事務(T1)讀取了幾行數(shù)據(jù),接著另一個并發(fā)事務(T2)插入了一些數(shù)據(jù)時术荤。在隨后的查詢中倚喂,第一個事務(T1)就會發(fā)現(xiàn)多了一些原本不存在的記錄,就好像發(fā)生了幻覺一樣瓣戚,所以稱為幻讀端圈。

不可重復度和幻讀區(qū)別:
不可重復讀的重點是修改,幻讀的重點在于新增或者刪除子库。

spring事務的傳播性舱权、隔離性

@Transactional
1.這里說明一下,有的把這個注解放在類名稱上面了刚照,這樣你配置的這個@Transactional 對這個類中的所有public方法都起作用.
2.@Transactional 方法方法名上刑巧,只對這個方法有作用,同樣必須是public的方法

我們在使用Spring聲明式事務時无畔,有一個非常重要的概念就是事務的屬性啊楚。事務屬性通常由事務的傳播行為、事務的隔離級別浑彰、事務的超時值和事務的只讀標識組成恭理。我們在進行事務劃分時,需要進行事務定義郭变,也就是配置事務的屬性颜价。

屏幕快照 2018-08-30 下午2.15.21.png

Spring在TransactionDefinition接口中定義這些屬性,以供PlatfromTransactionManager使用, PlatfromTransactionManager是spring事務管理的核心接口。

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 = 1;
    int ISOLATION_READ_COMMITTED = 2;
    int ISOLATION_REPEATABLE_READ = 4;
    int ISOLATION_SERIALIZABLE = 8;
    int TIMEOUT_DEFAULT = -1;

    int getPropagationBehavior();

    int getIsolationLevel();

    int getTimeout();

    boolean isReadOnly();

    String getName();
}

getTimeout()方法诉濒,它返回事務必須在多少秒內(nèi)完成周伦。
isReadOnly(),事務是否只讀,事務管理器能夠根據(jù)這個返回值進行優(yōu)化未荒,確保事務是只讀的专挪。
getIsolationLevel()方法返回事務的隔離級別,事務管理器根據(jù)它來控制另外一個事務可以看到本事務內(nèi)的哪些數(shù)據(jù)片排。

隔離級別

在TransactionDefinition接口中定義了五個不同的事務隔離級別 :
a) ISOLATION_DEFAULT:(PlatfromTransactionManager的)默認的隔離級別寨腔。使用數(shù)據(jù)庫默認的事務隔離級別(MySql 默認為 REPEATABLE_READ;Oracle 默認為:READ_COMMITTED)率寡,另外四個與JDBC的隔離級別相對應 迫卢。
b)ISOLATION_READ_UNCOMMITTED:這是事務最低的隔離級別,它允許別外一個事務可以看到這個事務未提交的數(shù)據(jù)冶共。這種隔離級別會產(chǎn)生臟讀乾蛤,不可重復讀和幻像讀每界。 (未解決任何并發(fā)問題)

例如:
Mary的原工資為1000,財務人員將Mary的工資改為了8000,但未提交事務

Connection con1 = getConnection();  
con1.setAutoCommit(false);  
update employee set salary = 8000 where empId ="Mary"; 

與此同時幻捏,Mary正在讀取自己的工資 盆犁。

Connection con2 = getConnection();  
select salary from employee where empId ="Mary";  
con2.commit();

Mary發(fā)現(xiàn)自己的工資變?yōu)榱?000命咐,歡天喜地篡九!
而財務發(fā)現(xiàn)操作有誤,而回滾了事務,Mary的工資又變?yōu)榱?000 醋奠。

con1.rollback(); 

像這樣,Mary記取的工資數(shù)8000是一個臟數(shù)據(jù)榛臼。

c)ISOLATION_READ_COMMITTED: 保證一個事務修改的數(shù)據(jù)提交后才能被另外一個事務讀取。另外一個事務不能讀取該事務未提交的數(shù)據(jù)窜司。這種事務隔離級別可以避免臟讀出現(xiàn)沛善,但是可能會出現(xiàn)不可重復讀和幻像讀。
d)ISOLATION_REPEATABLE_READ : 這種事務隔離級別可以防止臟讀塞祈,不可重復讀金刁。但是可能出現(xiàn)幻像讀。它除了保證一個事務不能讀取另一個事務未提交的數(shù)據(jù)外议薪,還保證了避免下面的情況產(chǎn)生(不可重復讀)尤蛮。

例如:
在事務1中,Mary 讀取了自己的工資為1000,操作并沒有完成 :

Connection con1 = getConnection();  
con1.setAutoCommit(false);  
select salary from employee empId ="Mary"; 

在事務2中斯议,這時財務人員修改了Mary的工資為2000,并提交了事務.

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

在事務1中产捞,Mary 再次讀取自己的工資時,工資變?yōu)榱?000

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

在一個事務中前后兩次讀取的結(jié)果并不致哼御,導致了不可重復讀坯临。
使用ISOLATION_REPEATABLE_READ可以避免這種情況發(fā)生。

e)ISOLATION_SERIALIZABLE 這是花費最高代價但是最可靠的事務隔離級別恋昼。事務被處理為順序執(zhí)行看靠。除了防止臟讀,不可重復讀外液肌,還避免了幻像讀挟炬。

例如:
目前工資為1000的員工有10人。
事務1,讀取所有工資為1000的員工矩屁。共讀取10條記錄

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

這時另一個事務向employee表插入了一條員工記錄辟宗,工資也為1000

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

事務1再次讀取所有工資為1000的員工

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

共讀取到了11條記錄,這就產(chǎn)生了幻像讀吝秕。
ISOLATION_SERIALIZABLE能避免這樣的情況發(fā)生泊脐。但是這樣也耗費了最大的資源。

事務的傳播性

在TransactionDefinition接口中定義了七個事務傳播行為烁峭。
假如我寫了兩個service類容客。名字分別為ServiceA和ServiceB秕铛。如下:

@Service("ServiceA")
public class ServiceA {

    @Resource(name="ServiceB")
    private ServiceB serviceB;

    @Transactional(propagation=Propagation.REQUIRED)
    public methodA(){
       //doSomething
       serviceB.methodB(); 
       //doSomething
    }
}
@Service("ServiceB")
public class ServiceB {

    @Transactional(propagation=Propagation.REQUIRED)
    public methodB(){
       //doSomething
    }
}

a)PROPAGATION_REQUIRED:如果存在一個事務,則支持當前事務缩挑。如果沒有事務則開啟一個新的事務但两。
如果單獨調(diào)用serviceB.methodB方法:

public static void main(String[] args) {
   serviceB.methodB();
}

相當于:

public static void main(String[] args) {
  Connection con=null;  
  try{  
      con = getConnection();  
      con.setAutoCommit(false);  
      //方法調(diào)用  
      methodB();  
      //提交事務  
      con.commit();  
 }Catch(RuntimeException ex){  
    //回滾事務  
    con.rollback();    
 }finally{  
    //釋放資源  
    closeCon();  
 }  
}  

Spring保證在methodB方法中所有的調(diào)用都獲得到一個相同的連接。在調(diào)用methodB時供置,沒有一個存在的事務谨湘,所以獲得一個新的連接,開啟了一個新的事務芥丧。

如果單獨調(diào)用MethodA時紧阔,在MethodA內(nèi)又會調(diào)用MethodB.
執(zhí)行效果相當于:

public static void main(String[] args) {
   Connection con = null;  
   try{  
      con = getConnection();  
      con.setAutoCommit(false);  
      methodA();  
      con.commit();  
   }cathc(RuntimeException ex){  
      con.rollback();  
   }finally{  
      closeCon();  
   }   
}  

調(diào)用MethodA時,環(huán)境中沒有事務续担,所以開啟一個新的事務.
當在MethodA中調(diào)用MethodB時擅耽,環(huán)境中已經(jīng)有了一個事務,所以methodB就加入當前事務物遇。

b)PROPAGATION_SUPPORTS :如果存在一個事務乖仇,支持當前事務。如果沒有事務询兴,則非事務的執(zhí)行乃沙。但是對于事務同步的事務管理器,PROPAGATION_SUPPORTS與不使用事務有少許不同蕉朵。

//事務屬性 PROPAGATION_REQUIRED   
methodA(){  
  serviceB.methodB();  
}  

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

單純的調(diào)用methodB時崔涂,methodB方法是非事務的執(zhí)行的。
當調(diào)用methdA時,methodB則加入了methodA的事務中,事務地執(zhí)行始衅。

c)PROPAGATION_MANDATORY :如果已經(jīng)存在一個事務冷蚂,支持當前事務。如果沒有一個活動的事務汛闸,則拋出異常蝙茶。

//事務屬性 PROPAGATION_REQUIRED   
methodA(){  
  serviceB.methodB();  
}  

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

當單獨調(diào)用methodB時,因為當前沒有一個活動的事務诸老,則會拋出異常
當調(diào)用methodA時隆夯,methodB則加入到methodA的事務中,事務地執(zhí)行别伏。

d)PROPAGATION_REQUIRES_NEW :總是開啟一個新的事務蹄衷。如果一個事務已經(jīng)存在,則將這個存在的事務掛起厘肮。

//事務屬性 PROPAGATION_REQUIRED   
methodA(){  
   doSomeThingA();  
   serviceB.methodB();  
   doSomeThingB();  
}  

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

當單獨調(diào)用methodB時愧口,相當于把methodB聲明為REQUIRED。開啟一個新的事務类茂,事務地執(zhí)行耍属。
當調(diào)用methodA時,情況就大不一樣了托嚣,相當于下面的效果。

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

在這里示启,我把ts1稱為外層事務,ts2稱為內(nèi)層事務领舰。從上面的代碼可以看出夫嗓,ts2與ts1是兩個獨立的事務,互不相干提揍。Ts2是否成功并不依賴于ts1啤月。如果methodA方法在調(diào)用methodB方法后的doSomeThingB方法失敗了,而methodB方法所做的結(jié)果依然被提交劳跃。而除了methodB之外的其它代碼導致的結(jié)果卻被回滾了。
使用PROPAGATION_REQUIRES_NEW,需要使用JtaTransactionManager作為事務管理器浙垫。

e)PROPAGATION_NOT_SUPPORTED: 總是非事務地執(zhí)行刨仑,并掛起任何存在的事務。

事務屬性 PROPAGATION_REQUIRED   
methodA(){  
  doSomeThingA();  
  serviceB.methodB();  
  doSomeThingB();  
}  

事務屬性 PROPAGATION_NOT_SUPPORTED   
methodB(){  
  ……  
}  

當單獨調(diào)用methodB時夹姥,不啟用任何事務機制杉武,非事務地執(zhí)行。
當調(diào)用methodA時辙售,相當于下面的效果

public static void main(String[] args) {
 TransactionManager tm = null;  
 try{  
  //獲得一個JTA事務管理器  
   tm = getTransactionManager();  
   tm.begin();//開啟一個新的事務  
   Transaction ts1 = tm.getTransaction();  
   doSomeThing();  
   tm.suspend();//掛起當前事務  
   methodB();  
   //methodB執(zhí)行完后轻抱,復恢第一個事務  
   tm.resume(ts1);  
   doSomeThingB();  
   ts1.commit();//提交第一個事務  
 }catch(RunTimeException ex){  
   ts1.rollback();//回滾第一個事務  
 }finally{  
  //釋放資源  
 }  
}  

使用PROPAGATION_NOT_SUPPORTED,也需要使用JtaTransactionManager作為事務管理器。

f)PROPAGATION_NEVER :總是非事務地執(zhí)行旦部,如果存在一個活動事務祈搜,則拋出異常:

事務屬性 PROPAGATION_REQUIRED   
methodA(){  
  doSomeThingA();  
  seviceB.methodB();  
  doSomeThingB();  
}  

事務屬性 PROPAGATION_NEVER   
methodB(){  
  ……  
}

單獨調(diào)用methodB,則非事務的執(zhí)行士八。 調(diào)用methodA則會拋出異常

g)PROPAGATION_NESTED:如果一個活動的事務存在容燕,則運行在一個嵌套的事務中. 如果沒有活動事務, 則按TransactionDefinition.PROPAGATION_REQUIRED 屬性執(zhí)行

這是一個嵌套事務,使用JDBC 3.0驅(qū)動時,僅僅支持DataSourceTransactionManager作為事務管理器。需要JDBC 驅(qū)動的java.sql.Savepoint類婚度。有一些JTA的事務管理器實現(xiàn)可能也提供了同樣的功能蘸秘。

使用PROPAGATION_NESTED,還需要把PlatformTransactionManager的nestedTransactionAllowed屬性設(shè)為true;
而nestedTransactionAllowed屬性值默認為false;

如下:

<bean id="system.platformTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">  
        <property name="sessionFactory" ref="system.sessionFactory"/>  
        <property name="nestedTransactionAllowed" value="true"/>  
 </bean>
事務屬性 PROPAGATION_REQUIRED   
methodA(){  
  doSomeThingA();  
  serviceB.methodB();  
  doSomeThingB();  
}  

事務屬性 PROPAGATION_NESTED  
methodB(){  
  ……  
} 

如果單獨調(diào)用methodB方法蝗茁,則按REQUIRED屬性執(zhí)行醋虏。
如果調(diào)用methodA方法,相當于下面的效果

main(){  
Connection con = null;  
Savepoint savepoint = null;  
try{  
  con = getConnection();  
  con.setAutoCommit(false);  
  doSomeThingA(); 
  //創(chuàng)造一個事務的保存點 
  savepoint = con2.setSavepoint();  
  try  
      methodB();  
  }catch(RuntimeException ex){  
     con.rollback(savepoint);  
  }finally{  
    //釋放資源  
  }  
  doSomeThingB();  
  con.commit();  
}catch(RuntimeException ex){  
  con.rollback();  
}finally{  
  //釋放資源  
}  
} 

當methodB方法調(diào)用之前哮翘,調(diào)用setSavepoint方法颈嚼,保存當前的狀態(tài)到savepoint。如果methodB方法調(diào)用失敗忍坷,則恢復到之前保存的狀態(tài)粘舟。但是需要注意的是熔脂,這時的事務并沒有進行提交,如果后續(xù)的代碼doSomeThingB()方法調(diào)用失敗柑肴,則回滾包括methodB方法的所有操作霞揉。

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

PROPAGATION_NESTED 與PROPAGATION_REQUIRES_NEW的區(qū)別:它們非常類似,都像一個嵌套事務硕舆,如果不存在一個活動的事務秽荞,都會開啟一個新的事務。使用PROPAGATION_REQUIRES_NEW時抚官,內(nèi)層事務與外層事務就像兩個獨立的事務一樣扬跋,一旦內(nèi)層事務進行了提交后,外層事務不能對其進行回滾凌节。兩個事務互不影響钦听。兩個事務不是一個真正的嵌套事務。同時它需要JTA事務管理器的支持倍奢。
使用PROPAGATION_NESTED時朴上,外層事務的回滾可以引起內(nèi)層事務的回滾。而內(nèi)層事務的異常并不會導致外層事務的回滾卒煞,它是一個真正的嵌套事務痪宰。DataSourceTransactionManager使用savepoint支持PROPAGATION_NESTED時,需要JDBC 3.0以上驅(qū)動及1.4以上的JDK版本支持畔裕。其它的JTA TrasactionManager實現(xiàn)可能有不同的支持方式衣撬。

PROPAGATION_REQUIRED應該是我們首先的事務傳播行為。它能夠滿足我們大多數(shù)的事務需求柴钻。

事務的超時性淮韭、回滾和只讀

  • 超時:
    @Transactional(timeout=30) //默認是30秒
    異常回滾:
    指定單一異常類:@Transactional(rollbackFor=RuntimeException.class)
    指定多個異常類:@Transactional(rollbackFor={RuntimeException.class, Exception.class})
    該屬性用于設(shè)置需要進行回滾的異常類數(shù)組贴届,當方法中拋出指定異常數(shù)組中的異常時靠粪,則進行事務回滾。

正常的情況下也可以回滾:
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

  • 只讀:
    @Transactional(readOnly=true)
    該屬性用于設(shè)置當前事務是否為只讀事務毫蚓,設(shè)置為true表示只讀占键,false則表示可讀寫,默認值為false元潘。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末畔乙,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子翩概,更是在濱河造成了極大的恐慌牲距,老刑警劉巖返咱,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異牍鞠,居然都是意外死亡咖摹,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門难述,熙熙樓的掌柜王于貴愁眉苦臉地迎上來萤晴,“玉大人,你說我怎么就攤上這事胁后〉甓粒” “怎么了?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵攀芯,是天一觀的道長屯断。 經(jīng)常有香客問我,道長敲才,這世上最難降的妖魔是什么裹纳? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮紧武,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘敏储。我一直安慰自己浇雹,他們只是感情好裕膀,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般换途。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上贞滨,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天拙吉,我揣著相機與錄音,去河邊找鬼缆蝉。 笑死宇葱,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的刊头。 我是一名探鬼主播黍瞧,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼原杂!你這毒婦竟也來了印颤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤穿肄,失蹤者是張志新(化名)和其女友劉穎年局,沒想到半個月后际看,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡矢否,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年仲闽,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片兴喂。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡蔼囊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出衣迷,到底是詐尸還是另有隱情畏鼓,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布壶谒,位于F島的核電站云矫,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏汗菜。R本人自食惡果不足惜让禀,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望陨界。 院中可真熱鬧巡揍,春花似錦、人聲如沸菌瘪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽俏扩。三九已至糜工,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間录淡,已是汗流浹背捌木。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留嫉戚,地道東北人刨裆。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像彼水,于是被迫代替她去往敵國和親崔拥。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345

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