Spring基礎(chǔ)篇(1)-事務(wù)

JAVA && Spring && SpringBoot2.x — 學(xué)習(xí)目錄

1. 編程式事務(wù)和聲明式事務(wù)

spring支持編程式事務(wù)管理聲明式事務(wù)管理兩種方式。

  • 編程式事務(wù)Spring推薦使用TransactionTemplate。需要在業(yè)務(wù)代碼中摻雜事務(wù)管理的代碼蜂厅,粒度可以作用到代碼塊級別廓旬。

  • 聲明式事務(wù)管理建立在AOP之上的纺座。其本質(zhì)是對方法前后進(jìn)行攔截荷腊,然后在目標(biāo)方法開始之前創(chuàng)建或者加入一個事務(wù)素征,在執(zhí)行完目標(biāo)方法之后根據(jù)執(zhí)行情況提交或者回滾事務(wù)。聲明式事務(wù)可以在配置文件中做相關(guān)的事務(wù)規(guī)則聲明(或基于@Transactional注解的方式)梧兼,不需要侵入業(yè)務(wù)代碼放吩。但是聲明式事務(wù)粒度只能做到方法級別。

Spring基于XML的聲明式事務(wù)配置:

  1. 配置事務(wù)管理器羽杰,將數(shù)據(jù)源交由事務(wù)管理器屎慢。
<bean id="transactionManager" class="...DataSourceTransactionManager">
     <property name="dataSource" ref="dataSource"/>
</bean>
  1. 配置事務(wù)通知,根據(jù)方法名忽洛,指定事務(wù)的屬性腻惠。
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="get*" read-only="true" propagation='"SUPPORTS">
        <tx:method name="purchase" protagation="REQUIRED">
    </tx:attributes>
</tx:advice>
  1. 配置aop,將事務(wù)和切點關(guān)聯(lián)起來欲虚。
<aop:config>
    <aop:pointcut expresssion="execution(* com.yxr.*(...))" id="txPointcut">
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>

Spring事務(wù)管理集灌,本質(zhì)上就是AOP編程的實現(xiàn),將數(shù)據(jù)源配置到數(shù)據(jù)管理器之后复哆。在配置事務(wù)通知欣喧,規(guī)定哪些方法需要事務(wù)。最后將事務(wù)通知和切點整合起來梯找。

Spring基于注解的聲明式事務(wù)配置:

  1. 配置事務(wù)管理器唆阿,將數(shù)據(jù)源交由事務(wù)管理器。
<bean id="transactionManager" class="...DataSourceTransactionManager">
     <property name="dataSource" ref="dataSource"/>
</bean>
  1. 啟動事務(wù)注解
<tx:annotation-driven transaction-manager="transactionManager">
  1. 可以在對應(yīng)方法上添加Transaction注解
@Transaction
public void purchase(){}

SpringBoot如何使用事務(wù):

Springboot默認(rèn)集成事物,只要在方法上加上@Transactional即可

2. Spring事務(wù)的使用和注意事項

說起來Spring事務(wù)锈锤,我們需要先讀一下系統(tǒng)之間那點事-異常知多少驯鳖,復(fù)習(xí)下Java異常的東西。

注意事項:

  1. @Transaction可以用于接口以及接口方法上久免,類以及類方法上浅辙。當(dāng)作用于類上時,該類的所有public方法都具有該類型的事務(wù)屬性阎姥。同時可以使用在方法級別使用注解來覆蓋類級別的定義记舆。
  2. Spring不建議@Transaction注解作用于接口以及接口方法上,因為這只有在使用基于接口的代理事務(wù)情況下才會生效呼巴。另外泽腮,@Transaction注解只能被應(yīng)用到public方法上,這是由于Spring AOP本質(zhì)上決定的衣赶,在其他訪問修飾符的方法使用@Transaction注解诊赊,事務(wù)不會起作用。
  3. 只有【外部方法】調(diào)用【事務(wù)方法】時才會被AOP代理捕獲屑埋,也就是說豪筝,類內(nèi)部方法調(diào)用本類事務(wù)方法并不會引起事務(wù)行為。(內(nèi)部方法使用this調(diào)用時:this為目標(biāo)對象)。
  4. Spring默認(rèn)情況下會對運(yùn)行期異常(非檢查異常RuntimeException)或者ERROR進(jìn)行回滾续崖∏媒郑可以使用rollbackFor=Exception.class對檢查時異常進(jìn)行回滾。
  5. MySQL事務(wù)庫表引擎應(yīng)為InnoDB严望,否則不支持事務(wù)多艇。

3. Spring事務(wù)的傳播行為

正如行為的英文含義,很好的解釋各種行為的含義:

事務(wù)的傳播(propagation [?pr?p?'ɡe??n])行為是指:如果在開始當(dāng)前事務(wù)之前像吻,一個事務(wù)上下文已經(jīng)存在峻黍,此時我們可以有多個選項指定事務(wù)性方法的執(zhí)行行為。

  1. PROPAGATION_REQUIRED:[adj 必須的]默認(rèn)傳播行為拨匆,指的是若當(dāng)前存在事務(wù)姆涩,則加入該事務(wù);如果當(dāng)前沒有事務(wù)惭每,則創(chuàng)建一個新事務(wù)骨饿。
  2. PROPAGATION_REQUIRES_NEW:[v 需要新的]需要創(chuàng)建一個新的,若當(dāng)前有事務(wù)台腥,則將當(dāng)前事務(wù)掛起宏赘。
  3. PROPAGATION_SUPPORTS:[v 支持]當(dāng)前存在事務(wù),就在事務(wù)中運(yùn)行黎侈;當(dāng)前不存在事務(wù)察署,則不在事務(wù)中運(yùn)行。
  4. PROPAGATION_NOT_SUPPORTED[v 不被支持]不運(yùn)行在事務(wù)中峻汉,當(dāng)前有事務(wù)贴汪,則掛掉當(dāng)前事務(wù)。
  5. PROPAGATION_NEVER:[adv 絕不]不運(yùn)行在事務(wù)中俱济,如果當(dāng)前有事務(wù)嘶是,則拋出異常。
  6. PROPAGATION_MANDARORY[[?m?nd?t?ri]強(qiáng)制的]`必須運(yùn)行在事務(wù)中蛛碌,如果當(dāng)前方法沒有事務(wù),則拋出異常辖源。
  7. PROPAGATION_NESTED[[nest?d] 嵌套的]當(dāng)前存在事務(wù)蔚携,則創(chuàng)建一個事務(wù)作為當(dāng)前事務(wù)的嵌套事務(wù)運(yùn)行,如果當(dāng)前沒有事務(wù)克饶,則創(chuàng)建一個新的事務(wù)酝蜒。

4. Spring事務(wù)隔離級別

隔離級別是指若干個并發(fā)事務(wù)之間的隔離(ISOLATION [?a?s??le??n])程度。

  1. READ_UNCOMMITTED:讀未提交矾湃,一個事務(wù)可以讀取到另一個事務(wù)未提交的數(shù)據(jù)亡脑。(臟讀,不可重復(fù)讀,幻讀)霉咨。
  2. READ_COMMITTED:讀已提交蛙紫,一個事務(wù)只能讀取另一個事務(wù)已經(jīng)提交的數(shù)據(jù)。(不可重復(fù)讀途戒,幻讀)坑傅。
  3. REPEATABLE_READ:可重復(fù)讀[r??pi:t?bl]一個事務(wù)在整個過程中多次重復(fù)執(zhí)行某個查詢,每次返回的結(jié)果都相同喷斋。(幻讀)
  4. SERIALIZABLE:序列化[s??r??la?'z?bl]所有事務(wù)依次逐個執(zhí)行唁毒,這樣事務(wù)之間不可能存在干擾。

5. Spring事務(wù)回滾規(guī)則

5.1 Exception異承亲Γ回滾事務(wù)

指示spring事務(wù)管理器回滾一個事務(wù)的推薦方法是在當(dāng)前事務(wù)的上下文拋出異常浆西。Spring事務(wù)管理器會捕獲任何未處理的異常,然后依據(jù)規(guī)則決定是否回滾拋出異常的事務(wù)顽腾。

默認(rèn)配置下近零,spring只有在拋出運(yùn)行時異常(RuntimeException及其子類)或者Error異常時才會回滾,但是可以配置rollbackFor=Exception.class檢查時異常進(jìn)行回滾崔泵。

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int addEmployee(Employee record) {
        int delResult = employeeMapper.deleteByPrimaryKey(11);
        int addResult = employeeMapper.insert(record);
        if (delResult == 0 || addResult == 0) {
            throw new RuntimeException("123");
        }
        return addResult;
    }

5.2 手動回滾事務(wù)

Spring事務(wù)原理就是AOP秒赤,即當(dāng)Spring捕獲住RuntimeException異常后,自動執(zhí)行【回滾】操作憎瘸。但是若不想拋出異常(捕獲處理異常)入篮,但依舊想回滾事務(wù),該如何處理幌甘?

我們可以使用TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();手動進(jìn)行回滾潮售,這樣上層便無需處理異常。

 @Transactional
    @Override
    public int addEmployee(Employee record) {
        int delResult = employeeMapper.deleteByPrimaryKey(11);
        int addResult = employeeMapper.insert(record);
        if (delResult == 0 || addResult == 0) {
            //手動回滾锅风,上層無需要處理異常酥诽。
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        return addResult;
    }

5.3 套嵌事務(wù)的回滾

spring 事務(wù)疑惑

情況大概是這樣的:

  1. 【事務(wù)嵌套調(diào)用】事務(wù)A方法調(diào)用了事務(wù)B方法;
  2. 【事務(wù)B出現(xiàn)異持宀海】事務(wù)A捕獲事務(wù)B的異常(其實事務(wù)A不想回滾)肮帐;
  3. 【事務(wù)A回滾操作】最終事務(wù)A還是回滾了;
public void testA() throws BussinessException {  
    try {  
        bService.testB();  
    } catch (BussinessException e) {  
        System.out.println(e.getErrorCode());  
    }  
    pictureService.addPicture("", "", "a.jpg", "", new File("d:/1.jpg"));  
}  
  <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">  
    <property name="sessionFactory" ref="sessionFactory" />  
</bean>  
  
<tx:advice id="txAdvice" transaction-manager="txManager">  
    <tx:attributes>  
        <tx:method name="*" rollback-for="com.soft.core.BussinessException" />  
    </tx:attributes>  
</tx:advice>  
  
<aop:config>  
    <aop:pointcut id="all" expression="execution(* com.soft.*.*.*ServiceImpl.*(..))"/>  
    <aop:advisor advice-ref="txAdvice" pointcut-ref="all"/>  
</aop:config>  

回答:
事務(wù)B方法的Transaction配置propagation屬性是使用的默認(rèn)值(required)边器。這樣的話训枢,本質(zhì)上事務(wù)A和事務(wù)B共用了一個Transaction。transactionManager中有一個參數(shù):globalRollbackOnParticipationFailure(參與者失敗導(dǎo)致全局回滾)

f (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {  
            if (defStatus.isDebug()) {  
                logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");  
            }  
            processRollback(defStatus);  
            // Throw UnexpectedRollbackException only at outermost transaction boundary  
            // or if explicitly asked to.  
            if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {  
                throw new UnexpectedRollbackException(  
                        "Transaction rolled back because it has been marked as rollback-only");  
            }  
            return;  
        }  

解決辦法:

  • 【方案一】如果想要事務(wù)B失敗不影響事務(wù)A忘巧,可以將事務(wù)B的傳播行為設(shè)置為propagation=Propagation.REQUIRES_NEW恒界。
  • 【方案二】將globalRollbackOnParticipationFailure參數(shù)設(shè)置為false。
  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
    <property name="globalRollbackOnParticipationFailure" value="false"/>
  </bean>

5.4 內(nèi)部方法調(diào)用事務(wù)方法

上面說到砚嘴,【外部方法】調(diào)用【事務(wù)方法】事務(wù)才會生效十酣;【內(nèi)部方法】調(diào)用【本類的事務(wù)方法】涩拙,事務(wù)不會起作用。

service層代碼

@Service
public class TestTransactionService {

    @Resource
    private UsertMapper usertMapper;

    //業(yè)務(wù)邏輯方法
    public void businessUsert(Usert usert) {
        insertUsert(usert);
        // 調(diào)用遠(yuǎn)程接口
    }

    @Transactional
    public void insertUsert(Usert usert) {
        usertMapper.insert(usert);
        throw new RuntimeException("拋出異常");
    }
}

Controller層代碼

@ResponseBody
    @RequestMapping(value = "user", method = RequestMethod.GET)
    public String showUserName() {
        Usert usert = new Usert();
        usert.setId(4);
        usert.setAge(20);
        usert.setUserName("李吉吉");
        usert.setPassword("123");
        testTransactionService.businessUsert(usert);
        return "success";
    }

執(zhí)行結(jié)果

16:21:31.251 [http-bio-8081-exec-1] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
16:21:31.264 [http-bio-8081-exec-1] DEBUG org.mybatis.spring.SqlSessionUtils - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5b9581da] was not registered for synchronization because synchronization is not active
16:21:31.354 [http-bio-8081-exec-1] DEBUG org.mybatis.spring.transaction.SpringManagedTransaction - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@429902b9] will not be managed by Spring
16:21:31.357 [http-bio-8081-exec-1] DEBUG com.springmvc.generic.mybatis.mapper.UsertMapper.insert - ooo Using Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@429902b9]
16:21:31.365 [http-bio-8081-exec-1] DEBUG com.springmvc.generic.mybatis.mapper.UsertMapper.insert - ==>  Preparing: insert into user_t (id, user_name, password, age) values (?, ?, ?, ?) 
16:21:31.552 [http-bio-8081-exec-1] DEBUG com.springmvc.generic.mybatis.mapper.UsertMapper.insert - ==> Parameters: 4(Integer), 李吉吉(String), 123(String), 20(Integer)
16:21:31.593 [http-bio-8081-exec-1] DEBUG org.mybatis.spring.SqlSessionUtils - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5b9581da]
16:21:31.597 [http-bio-8081-exec-1] INFO com.springmvc.common.GlobalExceptionHandler - 全局捕獲異常日志打印...
================全局捕獲異常=================
java.lang.RuntimeException: 拋出異常
    at com.springmvc.service.TestTransactionService.insertUsert(TestTransactionService.java:34)
    at com.springmvc.service.TestTransactionService.businessUsert(TestTransactionService.java:28)
    at com.springmvc.service.TestTransactionService$$FastClassBySpringCGLIB$$75b3ded0.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:640)
    at com.springmvc.service.TestTransactionService$$EnhancerBySpringCGLIB$$1b4acae.businessUsert(<generated>)
    at com.springmvc.web.UserController.showUserName(UserController.java:52)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

我們可以看到耸采,事務(wù)方法沒有生效(即沒有AOP增強(qiáng)兴泥,也沒有Rollback操作)。因為我們本類方法調(diào)用事務(wù)方法洋幻。

實際開發(fā)中郁轻,我們的【業(yè)務(wù)方法】中可能存在調(diào)用遠(yuǎn)程接口等耗時操作,需要將【事務(wù)】抽取出來文留,但【業(yè)務(wù)方法】調(diào)用【事務(wù)方法】事務(wù)不起作用好唯。那么如何解決?

解決方法:

@Service
public class TestTransactionService {

    @Resource
    private UsertMapper usertMapper;

    /**
     * 內(nèi)部方法調(diào)用本類事務(wù)方法的關(guān)鍵燥翅,重新進(jìn)行AOP增強(qiáng)
     */
    @Resource
    TestTransactionService testTransactionService;

    //業(yè)務(wù)邏輯方法
    public void businessUsert(Usert usert) {
        testTransactionService.insertUsert(usert);
    }

    @Transactional
    public void insertUsert(Usert usert) {
        usertMapper.insert(usert);
        throw new RuntimeException("拋出異常");
    }
}

日志打印

16:39:00.643 [http-bio-8081-exec-1] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
16:39:00.643 [http-bio-8081-exec-1] DEBUG org.mybatis.spring.SqlSessionUtils - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@508ee7ba]
16:39:00.644 [http-bio-8081-exec-1] DEBUG org.mybatis.spring.transaction.SpringManagedTransaction - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@4be855b6] will be managed by Spring
16:39:00.644 [http-bio-8081-exec-1] DEBUG com.springmvc.generic.mybatis.mapper.UsertMapper.insert - ooo Using Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@4be855b6]
16:39:00.644 [http-bio-8081-exec-1] DEBUG com.springmvc.generic.mybatis.mapper.UsertMapper.insert - ==>  Preparing: insert into user_t (id, user_name, password, age) values (?, ?, ?, ?) 
16:39:00.644 [http-bio-8081-exec-1] DEBUG com.springmvc.generic.mybatis.mapper.UsertMapper.insert - ==> Parameters: 4(Integer), 李吉吉(String), 123(String), 20(Integer)
16:39:00.646 [http-bio-8081-exec-1] DEBUG org.mybatis.spring.SqlSessionUtils - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@508ee7ba]
16:39:00.656 [http-bio-8081-exec-1] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization rolling back SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@508ee7ba]
16:39:00.656 [http-bio-8081-exec-1] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@508ee7ba]
16:39:00.658 [http-bio-8081-exec-1] INFO com.springmvc.common.GlobalExceptionHandler - 全局捕獲異常日志打印...
================全局捕獲異常=================
java.lang.RuntimeException: 拋出異常
    at com.springmvc.service.TestTransactionService.insertUsert(TestTransactionService.java:37)
    at com.springmvc.service.TestTransactionService$$FastClassBySpringCGLIB$$75b3ded0.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:708)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)
    at com.springmvc.service.TestTransactionService$$EnhancerBySpringCGLIB$$d0b071e3.insertUsert(<generated>)
    at com.springmvc.service.TestTransactionService.businessUsert(TestTransactionService.java:31)

在service類中骑篙,將【本類對象】引入【本類】中,可以看到內(nèi)部方法調(diào)用事務(wù)方法時森书,事務(wù)方法進(jìn)行了AOP增強(qiáng)靶端,即出現(xiàn)異常時回滾。

小伙伴會問凛膏,若是使用@Autowired注解會出現(xiàn)什么情況杨名?

當(dāng)使用@Autowired注解時,用來注入已有的bean猖毫。但是有些時候台谍,會注入失敗。原因就是@Autowired默認(rèn)就是@Autowired(required=true)吁断,表示注入的時候趁蕊,該bean必須存在,否則就會注入失敗仔役。

org.springframework.beans.factory.BeanCreationException: Error creating 
bean with name 'testTransactionService': Injection of autowired dependencies 
failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire
 field: com.springmvc.service.TestTransactionService 
com.springmvc.service.TestTransactionService.testTransactionService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
 No qualifying bean of type [com.springmvc.service.TestTransactionService] 
found for dependency: expected at least 1 bean which qualifies as autowire 
candidate for this dependency. Dependency annotations: 
{@org.springframework.beans.factory.annotation.Autowired(required=true)}

使用@Autowired注入屬性之后掷伙,會但是在bean容器中并沒有該類型的對象,于是在項目啟動的時候出現(xiàn)上圖的錯誤又兵,但若是我們設(shè)置@Autowired(required=false)后任柜,本質(zhì)上,該對象并未注入進(jìn)去沛厨,會出現(xiàn)空指針異常乘盼。

故:我們要使用@Resource屬性。

有些小伙伴會問俄烁,會不會出現(xiàn)循環(huán)依賴呢?

spring是將Bean對象實例化(依賴無參構(gòu)造函數(shù))级野,在設(shè)置對象屬性的值页屠。避免setter和field的循環(huán)依賴粹胯。

循環(huán)依賴其實就是循環(huán)引用,也就是兩個或者兩個以上的bean互相持有對象辰企,最終形成閉環(huán)风纠。

解決Spring循環(huán)依賴的依據(jù)其實是基于Java的引用傳遞,當(dāng)我們獲取對象引用時牢贸,對象的field是可以延后設(shè)置的竹观。【但構(gòu)造器必須是在獲取引用之前】潜索。

Spring單例對象初始化過程
  1. createBeanInstance:實例化臭增,其實就是調(diào)用對象的構(gòu)造方法實例化對象。
  2. populateBean:填充對象竹习,這一步主要是多bean的依賴屬性進(jìn)行填充誊抛。
  3. initializeBean:調(diào)用spring xml的init方法。

我們要解決循環(huán)引用也應(yīng)該是從初始化過程著手整陌,對于單例來說拗窃,在spring容器整個生命周期內(nèi),只有一個對象泌辫。保存在Cache中随夸。spring為解決單例的循環(huán)依賴問題,使用了三級緩存震放。

在createBeanInstance之后宾毒,其實單例對象已經(jīng)被創(chuàng)建出來(調(diào)用了構(gòu)造器),雖然不夠完美(未進(jìn)行初始化的第二步和第三步)澜搅,但是已經(jīng)能夠被認(rèn)出來(根據(jù)對象引用能定位到堆中的對象)伍俘。


Spring-bean的循環(huán)依賴以及解決方式

項目github地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市勉躺,隨后出現(xiàn)的幾起案子癌瘾,更是在濱河造成了極大的恐慌,老刑警劉巖饵溅,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件妨退,死亡現(xiàn)場離奇詭異,居然都是意外死亡蜕企,警方通過查閱死者的電腦和手機(jī)咬荷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來轻掩,“玉大人幸乒,你說我怎么就攤上這事〈侥粒” “怎么了罕扎?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵聚唐,是天一觀的道長。 經(jīng)常有香客問我腔召,道長杆查,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任臀蛛,我火速辦了婚禮亲桦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘浊仆。我一直安慰自己客峭,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布氧卧。 她就那樣靜靜地躺著桃笙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪沙绝。 梳的紋絲不亂的頭發(fā)上搏明,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機(jī)與錄音闪檬,去河邊找鬼星著。 笑死,一個胖子當(dāng)著我的面吹牛粗悯,可吹牛的內(nèi)容都是我干的虚循。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼样傍,長吁一口氣:“原來是場噩夢啊……” “哼横缔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起衫哥,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤茎刚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后撤逢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體膛锭,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年蚊荣,在試婚紗的時候發(fā)現(xiàn)自己被綠了初狰。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡互例,死狀恐怖奢入,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情媳叨,我是刑警寧澤俊马,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布丁存,位于F島的核電站,受9級特大地震影響柴我,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜扩然,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一艘儒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧夫偶,春花似錦界睁、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至说铃,卻和暖如春访惜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背腻扇。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工债热, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人幼苛。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓窒篱,卻偏偏與公主長得像,于是被迫代替她去往敵國和親舶沿。 傳聞我的和親對象是個殘疾皇子墙杯,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,877評論 2 345