MyBatis的事物管理和緩存

MyBatis的事物

事物的概念

在Java語言數(shù)據(jù)庫框架中富岳,數(shù)據(jù)庫的事務(wù)管理都是非常重要的诈茧。
每個業(yè)務(wù)邏輯都是由一系列數(shù)據(jù)庫訪問完成的刨仑,這些訪問可能修改多條數(shù)據(jù)記錄努释,這一系列修改應(yīng)該是一個整體拷泽,絕對不能只修改其中的某幾條數(shù)據(jù)記錄疫鹊。
多個數(shù)據(jù)庫原子訪問應(yīng)該被綁定成一個整體,這就是事物司致。事務(wù)是一步或幾步操作組成的邏輯執(zhí)行單元拆吆,這些基本操作作為一個整體執(zhí)行單元,它們要么全部執(zhí)行脂矫,要么全部取消執(zhí)行枣耀,絕對不能僅僅執(zhí)行一部分。
一個用戶請求對應(yīng)一個業(yè)務(wù)邏輯方法庭再,一個邏輯方法往往具有邏輯上的原子性捞奕,此時應(yīng)使用事物。
例如:一個轉(zhuǎn)賬操作拄轻,對應(yīng)修改兩個賬戶余額颅围,這兩個賬戶的修改要么同時生效,要么同時取消恨搓,同時生效是轉(zhuǎn)賬成功院促,同時取消是轉(zhuǎn)賬失敗斧抱;但不可只修改其中一個賬戶常拓,那將破壞數(shù)據(jù)庫的完整性。

事物的四個特性

  • 原子性:事物是應(yīng)用中最小的執(zhí)行單位夺姑,就如原子是自然界最小顆粒而不可以再分一樣墩邀,事物是應(yīng)用中不可再分的最小邏輯執(zhí)行體。
  • 一致性:事物的執(zhí)行結(jié)果盏浙,必須使數(shù)據(jù)庫從一種一致性狀態(tài)眉睹,變?yōu)榱硪环N一致性狀態(tài)。當數(shù)據(jù)庫只包含事物成功提交的結(jié)果時废膘,數(shù)據(jù)庫處于一致性狀態(tài)竹海。當系統(tǒng)運行發(fā)生中斷,某個事物尚未完成而被迫中斷丐黄,而該未完成的事物對數(shù)據(jù)庫所做的修改已被寫入數(shù)據(jù)庫斋配,此時,數(shù)據(jù)庫處于不正確的狀態(tài)。一致性是通過原子性來保證的艰争。
  • 隔離性:各個事物的執(zhí)行互不干擾坏瞄,任意一個事物的內(nèi)部操作對其他并發(fā)的事物,都是隔離的甩卓。
  • 持續(xù)性:持續(xù)性也被稱為持久性鸠匀,指事物一旦提交,對數(shù)據(jù)所做的任何改變都要記錄到用就存儲器中逾柿,通常是保存到物理數(shù)據(jù)庫缀棍。

Transaction接口

對數(shù)據(jù)庫事物而言,應(yīng)具有:創(chuàng)建机错、提交爬范、回滾、關(guān)閉幾個動作弱匪,MyBatis的事物設(shè)計重點是org.apache.ibatis.transaction.Transaction接口青瀑,該接口源碼如下:

public interface Transaction {
    Connection getConnection() throws SQLException;

    void commit() throws SQLException;

    void rollback() throws SQLException;

    void close() throws SQLException;

    Integer getTimeout() throws SQLException;
}

Transaction接口有兩個實現(xiàn)類:org.apache.ibatis.transaction.jdbc.JdbcTransaction和org.apache.ibatis.transaction.managed.ManagedTransaction。
所以MyBatis的事務(wù)管理有兩種形式:

  • 使用JDBC的事物管理機制痢法,利用java.sql.Connection對象完成對事物的提交狱窘、回滾、關(guān)閉等操作财搁。
  • 使用MANAGED的事物管理機制蘸炸,MyBatis自身不會去實現(xiàn)事務(wù)管理,而是讓容器如WebLogic尖奔、JBOSS等來實現(xiàn)對事物的管理搭儒。

事物的創(chuàng)建和使用

在使用MyBatis的時候,會在MyBatis的配置文件mybatis-config.xml中定義提茁,此處使用前文(http://www.reibang.com/p/063a5ca8874c)配置信息:

<environment id="mysql">
            <!--指定事務(wù)管理的類型淹禾,這里簡單使用Java的JDBC的提交和回滾設(shè)置-->
            <transactionManager type="JDBC"></transactionManager>
            <!--dataSource 指連接源配置,POOLED是JDBC連接對象的數(shù)據(jù)源連接池的實現(xiàn)-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"></property>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useUnicode=true&amp;characterEncoding=UTF-8"></property>
                <property name="username" value="root"></property>
                <property name="password" value="****"></property>
            </dataSource>
        </environment>

<environment>元素定義了連接數(shù)據(jù)庫的信息茴扁,<transactionManager>子元素的type決定了使用什么類型的事物管理機制铃岔。

MyBatis的緩存

緩存的概述

在實際項目開發(fā)中,通常對數(shù)據(jù)庫查詢的性能要求很高峭火,MyBatis提供了查詢緩存來進行數(shù)據(jù)的緩存毁习,以達到提高查詢性能的要求。
MyBatis的查詢緩存分為一級緩存和二級緩存:

  • 一級緩存是SqlSession級別的緩存卖丸。
  • 二級緩存是mapper級別的緩存纺且,二級緩存是多個SqlSession共享的。

MyBatis通過緩存機制減輕數(shù)據(jù)壓力稍浆,提高數(shù)據(jù)庫性能载碌。

一級緩存

在操作數(shù)據(jù)庫時需要構(gòu)造SqlSession對象猜嘱,在對象中有一個HashMap用戶緩存數(shù)據(jù)。不同的SqlSession之間的緩存數(shù)據(jù)區(qū)域(HashMap)是互相不影響的嫁艇。
一級緩存的作用是SqlSession范圍的朗伶,當同一個SqlSession中執(zhí)行兩次相同的sql語句時,第一次執(zhí)行完畢會將數(shù)據(jù)庫中查詢的數(shù)據(jù)寫到緩存(內(nèi)存)步咪,第二次查詢時會從緩存中獲取數(shù)據(jù)腕让,不再去底層數(shù)據(jù)庫查詢,提高查詢效率歧斟。
\color{red}{注意:}
若SqlSession執(zhí)行了DML操作(insert、update和delete)偏形,并提交到數(shù)據(jù)庫静袖,MyBatis則會清空SqlSession中的一級緩存,目的是為了保證緩存中存儲的是最新的數(shù)據(jù)俊扭,避免臟讀現(xiàn)象队橙。
當一個SqlSession結(jié)束后,該SqlSession中的一級緩存也就不存在了萨惑。
\color{red}{MyBatis默認開啟一級緩存捐康,不需要進行任何配置。}

一級緩存測試

項目代碼使用前文項目(http://www.reibang.com/p/063a5ca8874c
現(xiàn)在數(shù)據(jù)庫的tb_user表中插入幾條數(shù)據(jù):

MyBatis01.png

然后在項目的UserMapper.xml文件中添加查詢和刪除程序庸蔼,完整程序如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.snow.dcl.mapper.UserMapper">
    <!--插入用戶數(shù)據(jù)-->
    <insert id="saveUser" parameterType="com.snow.dcl.domain.User" useGeneratedKeys="true">
        insert into tb_user(name,sex,age) values (#{name},#{sex},#{age});
    </insert>
    <!--根據(jù)id查詢用戶-->
    <select id="selectUserById" parameterType="int" resultType="com.snow.dcl.domain.User">
        select * from tb_user where id=#{id};
    </select>
    <!--查詢所有用戶-->
    <select id="selectAllUser" resultType="com.snow.dcl.domain.User">
        select * from tb_user;
    </select>
    <!--根據(jù)id刪除用戶-->
    <delete id="deleteUserById" parameterType="int">
        delete from tb_user where id=#{id};
    </delete>
</mapper>

在項目的java目錄右鍵解总,創(chuàng)建com.snow.dcl.mapper包,在該包中創(chuàng)建UserMapper.java接口類:


MyBatis02.png

編寫如下程序:

public interface UserMapper {
    //根據(jù)id查詢用戶
    User selectUserById(Integer id);
    //查詢所有用戶
    List<User> selectAllUser();
    //根據(jù)id刪除用戶
    void deleteUserById(Integer id);
}

獲取mybatis-config.xml配置文件姐仅,根據(jù)配置文件創(chuàng)建SqlSessionFactory花枫,獲取SqlSession對象這一系列操作,每次都要使用掏膏,所以將其封裝在一個類文件中劳翰,在項目java目錄右鍵,創(chuàng)建com.snow.dcl.utils包馒疹,在該包下創(chuàng)建FactoryUtil.java類文件:


MyBatis03.png

添加如下程序:

public class FactoryUtil {
    private static SqlSessionFactory sqlSessionFactory = null;

    static {
        try {
            InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}

在項目的test目錄下的java目錄下創(chuàng)建OneLevelCacheTest.java測試類文件:


MyBatis04.png

編寫如下程序:

public class OneLevelCacheTest {
    public static void main(String[] args) {
        OneLevelCacheTest oneLevelCacheTest = new OneLevelCacheTest();
        oneLevelCacheTest.cacheOneTest();
    }

    public void cacheOneTest(){
        SqlSession sqlSession = FactoryUtil.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user = userMapper.selectUserById(1);
        System.out.println(user);
        User anotherUser = userMapper.selectUserById(1);
        System.out.println(anotherUser);
        sqlSession.close();
    }
}

執(zhí)行測試程序OneLevelCacheTest1.java佳簸,可以在控制臺看到打印結(jié)果:


MyBatis05.png

可以看到在第一次執(zhí)行查詢id為1的User對象時,執(zhí)行了一條select語句颖变,第二次執(zhí)行查詢id為1的User對象時生均,沒有執(zhí)行select語句,因為此時一級緩存中已經(jīng)緩存了id為1的User對象悼做,MyBatis直接從緩存中將User對象取出來疯特,并沒有再次去數(shù)據(jù)庫中查詢。

DML操作清空緩存

在項目的test目錄下的java目錄創(chuàng)建OneLevelCacheTest2測試類文件肛走,編寫如下代碼:

public class OneLevelCacheTest2 {
    public static void main(String[] args) {
        OneLevelCacheTest2 oneLevelCacheTest = new OneLevelCacheTest2();
        oneLevelCacheTest.cacheOneTest();
    }

    public void cacheOneTest(){
        SqlSession sqlSession = FactoryUtil.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user = userMapper.selectUserById(1);
        System.out.println(user);
        userMapper.deleteUserById(7);
        sqlSession.commit();
        User anotherUser = userMapper.selectUserById(1);
        System.out.println(anotherUser);
        sqlSession.close();
    }
}

執(zhí)行測試程序OneLevelCacheTest2.java漓雅,可以在控制臺看到打印結(jié)果:


MyBatis06.png

可以看到在第一次執(zhí)行查詢id為1的User對象時,執(zhí)行了一條select語句,接下來執(zhí)行了一個delete操作邻吞,MyBatis為了保證緩存中存儲的是最新的數(shù)據(jù)组题,清空了一級緩存,所以第二次執(zhí)行查詢id為1的User對象時抱冷,又執(zhí)行了select語句崔列。

不同Session對象對一級緩存的影響

在項目的test目錄下的java目錄創(chuàng)建OneLevelCacheTest3測試類文件,編寫如下代碼:

public class OneLevelCacheTest3 {
    public static void main(String[] args) {
        OneLevelCacheTest3 oneLevelCacheTest = new OneLevelCacheTest3();
        oneLevelCacheTest.cacheOneTest();
    }

    public void cacheOneTest(){
        SqlSession sqlSession = FactoryUtil.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user = userMapper.selectUserById(1);
        System.out.println(user);
        sqlSession.close();
        sqlSession = FactoryUtil.getSqlSession();
        userMapper = sqlSession.getMapper(UserMapper.class);
        User anotherUser = userMapper.selectUserById(1);
        System.out.println(anotherUser);
        sqlSession.close();
    }
}

執(zhí)行測試程序OneLevelCacheTest2.java旺遮,可以在控制臺看到打印結(jié)果:


MyBatis07.png

可以看到在第一次執(zhí)行查詢id為1的User對象時赵讯,執(zhí)行了一條select語句,接下來調(diào)用了sqlSession.close()關(guān)閉了一級緩存耿眉,第二次執(zhí)行查詢id為1的User對象時边翼,一級緩存是一個新的對象,緩存中沒有緩存任何數(shù)據(jù)鸣剪,所以再次執(zhí)行了select語句组底。

二級緩存

使用二級緩存時,多個SqlSession使用同一個Mapper的sql語句去操作數(shù)據(jù)庫筐骇,得到的數(shù)據(jù)會存在二級緩存區(qū)域债鸡,它同樣是使用HashMap進行數(shù)據(jù)存儲。相比一級緩存SqlSession铛纬,二級緩存的范圍更大厌均,多個SqlSession可以共用二級緩存,二級緩存是跨SqlSession的饺鹃。
二級緩存是多個SqlSession共享的莫秆,其作用域是mapper的同一個namespace。不同的SqlSession兩次執(zhí)行相同namespace下的sql語句悔详,且向sql中傳遞的參數(shù)也相同镊屎,即最終執(zhí)行相同的sql語句,則第一次執(zhí)行完畢會將數(shù)據(jù)庫中查詢的數(shù)據(jù)寫入緩存茄螃,第二次查詢時會從緩存中獲取數(shù)據(jù)缝驳,不再去底層數(shù)據(jù)庫查詢,提高效率归苍。
\color{red}{MyBatis默認沒有開啟二級緩存用狱,需要在setting全局參數(shù)中進行配置,開啟二級緩存拼弃。}

二級緩存測試

在mubatis-config.xml配置文件中開啟二級緩存夏伊,完整配置文件如下:

<configuration>
    <!-- 指定Mybatis所用日志的具體實現(xiàn) -->
    <settings>
        <!--開啟二級緩存-->
        <setting name="cacheEnabled" value="true"/>
        <!--開啟日志-->
        <setting name="logImpl" value="Log4J"/>
    </settings>
    <!--環(huán)境配置,連接的數(shù)據(jù)庫-->
    <environments default="mysql">
        <environment id="mysql">
            <!--指定事務(wù)管理的類型吻氧,這里簡單使用Java的JDBC的提交和回滾設(shè)置-->
            <transactionManager type="JDBC"></transactionManager>
            <!--dataSource 指連接源配置溺忧,POOLED是JDBC連接對象的數(shù)據(jù)源連接池的實現(xiàn)-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"></property>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useUnicode=true&amp;characterEncoding=UTF-8"></property>
                <property name="username" value="root"></property>
                <property name="password" value="Password@123"></property>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--告訴Mybatis持久化類的映射文件路徑-->
        <mapper resource="mapping/UserMapper.xml"></mapper>
    </mappers>
</configuration>

cacheEnabled默認為false咏连,設(shè)置為true表示開啟二級緩存。
在UserMapper.sml文件配置緩存相關(guān)參數(shù)鲁森,完整配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.snow.dcl.mapper.UserMapper">
    <!--開啟當前mapper的namespace下的二級緩存-->
    <cache eviction="LRU" flushInterval="20000" size="512" readOnly="true"/>
    <!--插入用戶數(shù)據(jù)-->
    <insert id="saveUser" parameterType="com.snow.dcl.domain.User" useGeneratedKeys="true">
        insert into tb_user(name,sex,age) values (#{name},#{sex},#{age});
    </insert>
    <!--根據(jù)id查詢用戶-->
    <select id="selectUserById" parameterType="int" resultType="com.snow.dcl.domain.User">
        select * from tb_user where id=#{id};
    </select>
    <!--查詢所有用戶-->
    <select id="selectAllUser" resultType="com.snow.dcl.domain.User">
        select * from tb_user;
    </select>
    <!--根據(jù)id刪除用戶-->
    <delete id="deleteUserById" parameterType="int">
        delete from tb_user where id=#{id};
    </delete>
</mapper>

參數(shù)解釋:

  • eviction:回收策略祟滴,默認為LRU,此外還有FIFO歌溉、SOFT垄懂、WEAK。
    LRU:最近最少使用策略痛垛,移除最長時間不被使用的對象草慧。
    FIFO:先進先出策略,按對象進入緩存的順序來移除匙头。
    SOFT:軟引用策略冠蒋,移除基于垃圾回收器狀態(tài)和軟引用規(guī)則的對象。
    WEAK:弱引用策略乾胶,更積極地移除基于垃圾收集器狀態(tài)和弱引用規(guī)則的對象。
  • flushInterval:刷新間隔時間朽寞,任意正整數(shù)识窿,單位毫秒,默認情況下是沒有刷新間隔脑融,緩存僅在調(diào)用語句時刷新喻频。
  • size:緩存數(shù)目,任意正整數(shù)肘迎,要記住緩存的對象數(shù)目與運行環(huán)境的可用內(nèi)存資源數(shù)目甥温,默認1024。
  • readOnly:只讀妓布,屬性為true或false姻蚓。true緩存會給所有調(diào)用者返回緩存對象的相同實例,對象不能修改匣沼,性能高狰挡。false緩存會返回緩存對象的拷貝(通過序列化),性能低释涛,但是安全加叁。默認為false。
    \color{red}{注意:}
    使用二級緩存時唇撬,與查詢結(jié)果映射的Java對象必須實現(xiàn)java.io.Serializable接口的序列化和反序列化操作它匕,若存在父類,其成員都要實現(xiàn)序列化接口窖认。實現(xiàn)該接口的原因是為了對緩存數(shù)據(jù)進行序列化和反序列化操作豫柬,因為二級緩存數(shù)據(jù)存儲介質(zhì)多種多樣告希,不一定在內(nèi)存,可能是硬盤或者遠程服務(wù)器轮傍。
    在項目的test目錄下的java目錄下創(chuàng)建TwoLevelCacheTest1.java測試類文件暂雹,編寫如下代碼:
public class TwoLevelCacheTest1 {
    public static void main(String[] args) {
        TwoLevelCacheTest1 twoLevelCacheTest = new TwoLevelCacheTest1();
        twoLevelCacheTest.cacheTwoTest();
    }

    public void cacheTwoTest(){
        SqlSession sqlSession = FactoryUtil.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user = userMapper.selectUserById(1);
        System.out.println(user);
        sqlSession.close();
        sqlSession = FactoryUtil.getSqlSession();
        userMapper = sqlSession.getMapper(UserMapper.class);
        User anotherUser = userMapper.selectUserById(1);
        System.out.println(anotherUser);
        sqlSession.close();
    }
}

執(zhí)行測試程序TwoLevelCacheTest.java,可以在控制臺看到打印結(jié)果:

MyBatis08.png

可以看到在第一次執(zhí)行查詢id為1的User對象時创夜,執(zhí)行了一條select語句杭跪,接下來調(diào)用了sqlSession.close()關(guān)閉了一級緩存,第二次執(zhí)行查詢id為1的User對象時驰吓,一級緩存沒有任何對象涧尿,但因為啟用了二級緩存,第一次查詢的數(shù)據(jù)會緩存在二級緩存中檬贰,所以顯示命中二級緩存數(shù)據(jù)姑廉,不需要在執(zhí)行select語句。

在UserMapper.xml文件的select語句中設(shè)置useCache='false'翁涤,可以禁用當前select語句的二級緩存桥言,即每次都會查詢數(shù)據(jù)庫,默認為true葵礼,配置內(nèi)容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.snow.dcl.mapper.UserMapper">
    <!--開啟當前mapper的namespace下的二級緩存-->
    <cache eviction="LRU" flushInterval="20000" size="512" readOnly="true"/>
    <!--插入用戶數(shù)據(jù)-->
    <insert id="saveUser" parameterType="com.snow.dcl.domain.User" useGeneratedKeys="true">
        insert into tb_user(name,sex,age) values (#{name},#{sex},#{age});
    </insert>
    <!--根據(jù)id查詢用戶-->
    <select id="selectUserById" parameterType="int" resultType="com.snow.dcl.domain.User" useCache="false">
        select * from tb_user where id=#{id};
    </select>
    <!--查詢所有用戶-->
    <select id="selectAllUser" resultType="com.snow.dcl.domain.User">
        select * from tb_user;
    </select>
    <!--根據(jù)id刪除用戶-->
    <delete id="deleteUserById" parameterType="int">
        delete from tb_user where id=#{id};
    </delete>
</mapper>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末号阿,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子鸳粉,更是在濱河造成了極大的恐慌扔涧,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件届谈,死亡現(xiàn)場離奇詭異枯夜,居然都是意外死亡,警方通過查閱死者的電腦和手機艰山,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門湖雹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人曙搬,你說我怎么就攤上這事劝枣。” “怎么了织鲸?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵舔腾,是天一觀的道長。 經(jīng)常有香客問我搂擦,道長稳诚,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任瀑踢,我火速辦了婚禮扳还,結(jié)果婚禮上才避,老公的妹妹穿的比我還像新娘。我一直安慰自己氨距,他們只是感情好桑逝,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著俏让,像睡著了一般楞遏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上首昔,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天寡喝,我揣著相機與錄音,去河邊找鬼勒奇。 笑死预鬓,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的赊颠。 我是一名探鬼主播格二,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼竣蹦!你這毒婦竟也來了蟋定?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤草添,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后扼仲,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體远寸,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年屠凶,在試婚紗的時候發(fā)現(xiàn)自己被綠了驰后。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡矗愧,死狀恐怖灶芝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情唉韭,我是刑警寧澤夜涕,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站属愤,受9級特大地震影響女器,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜住诸,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一驾胆、第九天 我趴在偏房一處隱蔽的房頂上張望涣澡。 院中可真熱鬧,春花似錦丧诺、人聲如沸入桂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽抗愁。三九已至,卻和暖如春搞隐,著一層夾襖步出監(jiān)牢的瞬間驹愚,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工劣纲, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留逢捺,地道東北人。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓癞季,卻偏偏與公主長得像劫瞳,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子绷柒,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

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