今天二面,我和面試官聊了半天的 MyBatis

?昨天剛剛面完 Spring,根據(jù)hr的反饋說(shuō)面試官對(duì)我的整體表現(xiàn)還算滿意,然后又通知我今天有空去再聊聊有關(guān)的技術(shù)。去的路上,我一直在想,今天會(huì)問(wèn)些什么問(wèn)題,JVM?多線程?還是分布式......真是越想心里越?jīng)]底。

想著想著就到了,盡管還是那個(gè)熟悉的面試官,但那張年輕有為的面孔絲毫沒(méi)有讓我放下緊張的情緒。

他先開(kāi)口了:昨天的面試感覺(jué)你挺好的,你說(shuō)你項(xiàng)目中還用的是mybatis框架作為數(shù)據(jù)庫(kù)訪問(wèn),那我們今天就來(lái)聊聊吧。

面試官:你先說(shuō)下你對(duì)mybatis的整體理解。

我:MyBatis是支持定制化SQL、存儲(chǔ)過(guò)程以及高級(jí)映射的優(yōu)秀的持久層框架。它避免了幾乎所有JDBC代碼和手動(dòng)設(shè)置參數(shù)以及獲取結(jié)果集。MyBatis可以對(duì)配置和原生Map使用簡(jiǎn)單的XML或注解,將接口和Java的POJO映射成數(shù)據(jù)庫(kù)中的記錄。

面試官:那你們公司為什么選擇Mybatis,為什么不用Hibernate呢?他兩有什么區(qū)別嗎?

我:mybatis的著力點(diǎn)在于POJO和SQL之間的映射關(guān)系,然后通過(guò)映射配置文件,將SQL所需的參數(shù),以及返回的結(jié)果字段映射到指定POJO。Hibernate的ORM實(shí)現(xiàn)了POJO和數(shù)據(jù)庫(kù)表之間的映射,以及SQl的自動(dòng)生成和執(zhí)行,也就是說(shuō)Hibernate會(huì)根據(jù)制定的存儲(chǔ)邏輯,自動(dòng)生成對(duì)應(yīng)的SQl并調(diào)用JDBC接口加以執(zhí)行。

下面我通過(guò)四個(gè)方面對(duì)比兩者的區(qū)別:

1、開(kāi)發(fā)對(duì)比:

mybatis框架相對(duì)簡(jiǎn)單容易上手,針對(duì)高級(jí)查詢,Mybatis需要手動(dòng)編寫(xiě)SQL語(yǔ)句。

Hibernate的真正掌握要比MyBatis難一些,Hibernate有良好的的映射機(jī)制,開(kāi)發(fā)者無(wú)需關(guān)心SQL的生成與結(jié)果映射,可以更關(guān)注業(yè)務(wù)流程。

2、調(diào)優(yōu)方案:

mybatis可以進(jìn)行詳細(xì)的SQL優(yōu)化設(shè)計(jì),采用合理的session管理機(jī)制。

Hibernate可以指定合理的緩存策略;

盡量采用延遲加載特性;

采用合理的session管理機(jī)制;

采用批量抓取,設(shè)定合理的批處理參數(shù)。

3、擴(kuò)展性方面:

mybatis項(xiàng)目中的所有SQL語(yǔ)句都是依賴所用的數(shù)據(jù)庫(kù)的,所以不同數(shù)據(jù)庫(kù)類型的支持不好。Hibernate與具體數(shù)據(jù)庫(kù)的關(guān)聯(lián)只需在XML文件中配置即可,所有的HQL語(yǔ)句與具體使用的數(shù)據(jù)庫(kù)無(wú)關(guān),移植性很好。

4、緩存機(jī)制:

mybatis默認(rèn)情況下沒(méi)開(kāi)啟緩存;要開(kāi)啟二級(jí)緩存,需要在sql映射文件中加上;映射文件中的所有select語(yǔ)句將會(huì)緩存,映射文件中的所有insert/update/delete會(huì)刷新緩存;

緩存會(huì)使用LRU(最近最少使用)算法來(lái)回收;

緩存會(huì)存儲(chǔ)列表集合會(huì)對(duì)象的1024個(gè)引用;

緩存會(huì)被視為read/write(可讀可寫(xiě))緩存,意味著對(duì)象檢索不是共享的,而且可以安全地被調(diào)用者修改,而不干擾其他調(diào)用者或線程所做的潛在修改。

Hibernate的一級(jí)緩存是Session緩存,利用好一級(jí)緩存就需要對(duì)Session的生命周期進(jìn)行管理好;二級(jí)緩存是SessionFactory級(jí)的緩存,分為內(nèi)置緩存和外置緩存。

另外,有種說(shuō)法,mybatis是半自動(dòng)ORM映射工具,Hibernate是全自動(dòng)的。這主要就是因?yàn)槭褂肏ibernate查詢關(guān)聯(lián)對(duì)象或集合對(duì)象時(shí),可以根據(jù)對(duì)象關(guān)系模型調(diào)用api接口直接獲取。而Mybatis在查詢關(guān)聯(lián)對(duì)象或集合對(duì)象時(shí),需要手動(dòng)編寫(xiě)sql來(lái)完成,所以叫做半自動(dòng)。

至于我們公司為什么選擇半自動(dòng)的mybatis,主要是因?yàn)槲覀兊臉I(yè)務(wù)經(jīng)常需要編寫(xiě)復(fù)雜的sql,比如動(dòng)態(tài)的sql。還有這種更便于我們使用索引來(lái)優(yōu)化sql語(yǔ)句。

面試官:你先說(shuō)下JDBC的執(zhí)行流程吧

我:

1、加載JDBC驅(qū)動(dòng)

2、建立并獲取數(shù)據(jù)庫(kù)連接

3、創(chuàng)建JDBC Statements對(duì)象

4、設(shè)置SQL語(yǔ)句的傳入?yún)?shù)

5、執(zhí)行SQL語(yǔ)句并獲得查詢結(jié)果

6、對(duì)查詢結(jié)果進(jìn)行轉(zhuǎn)換處理并將處理結(jié)果返回

7、釋放相關(guān)資源(關(guān)閉Connection,關(guān)閉Statement,關(guān)閉ResultSet)

面試官:那你能說(shuō)下mybatis執(zhí)行SQL的流程嗎?

我:好的。

1、加載配置并初始化:

加載配置文件,將SQl配置信息加載成為一個(gè)個(gè)MappedStatement對(duì)象(包括傳入?yún)?shù)映射配置,執(zhí)行的sql語(yǔ)句,結(jié)果映射的配置),存儲(chǔ)在內(nèi)存中。

2、傳遞調(diào)用請(qǐng)求:

調(diào)用Mybatis提供的API,傳入SQL的ID和參數(shù)對(duì)象,將請(qǐng)求傳遞給下層的請(qǐng)求處理層進(jìn)行處理。

3、處理請(qǐng)求:

根據(jù)SQL的ID查找到對(duì)應(yīng)的MappedStatement對(duì)象;

根據(jù)傳入的參數(shù)對(duì)象解析MappedStatement對(duì)象,得到最終要執(zhí)行的SQL和執(zhí)行參數(shù);

獲取數(shù)據(jù)庫(kù)連接,根據(jù)得到的SQL語(yǔ)句和執(zhí)行參數(shù)到數(shù)據(jù)庫(kù)中執(zhí)行,并得到執(zhí)行結(jié)果;

根據(jù)MappedStatement對(duì)象中的結(jié)果映射配置對(duì)得到的執(zhí)行結(jié)果進(jìn)行轉(zhuǎn)換處理,得到最終的處理結(jié)果;

釋放連接資源;

將最終的結(jié)果返回。

總之,這個(gè)過(guò)程就是:

加載配置->SQL解析->SQL執(zhí)行->結(jié)果映射->釋放連接

面試官:很好。你剛說(shuō)到初始化,你對(duì)mybatis初始化了解嗎?

我:可以這么說(shuō),Myabtis初始化的過(guò)程就是創(chuàng)建Configuration對(duì)象的過(guò)程。

過(guò)程也很簡(jiǎn)單:

1、加載配置文件mybatis-config.xml到Mybatis內(nèi)部。

2、使用Configuration對(duì)象作為一個(gè)所有配置信息的容器,這個(gè)對(duì)象的組織結(jié)構(gòu)和XML配置文件的組織結(jié)構(gòu)幾乎完全一樣,這樣配置文件的信息就可以存到這個(gè)對(duì)象中,訪問(wèn)起來(lái)很方便。

面試官:那我問(wèn)的再深入一點(diǎn),你看過(guò)mybatis的源碼嗎?

我:沒(méi)看過(guò)。。關(guān)鍵的類還是知道一點(diǎn)的。

面試官:哦,那你說(shuō)下你了解的mybatis的有哪些核心的類?

我:(心想:既然面試前準(zhǔn)備了,還是要說(shuō)的,不然怎么顯得自己nb一些)

第一個(gè)是SqlSessionFactoryBuilder:

通過(guò)類名就看出來(lái)這個(gè)類的主要作用是創(chuàng)建一個(gè)SqlSessionFactory。

可以重用這個(gè)類來(lái)創(chuàng)建多個(gè)SqlSessionFactory實(shí)例,但是最好不要讓其一直存在以保證所有的XML解析資源開(kāi)放給更重要的事情。

這個(gè)類可以被實(shí)例化、使用和丟棄,一旦創(chuàng)建了SqlSessionFactory,就不再需要它了。

第二個(gè)是SqlSessionFactory接口:

它的作用就是sql會(huì)話工廠,用于創(chuàng)建SqlSession。

SqlSessionFactory一旦被創(chuàng)建就應(yīng)該在應(yīng)用的運(yùn)行期間一直存在,它的最佳作用域是應(yīng)用作用域。

第三個(gè)是很重要的SqlSession接口:

他是mybatis的一個(gè)重要接口,定義了數(shù)據(jù)庫(kù)的增刪改查以及事務(wù)管理的常用方法。

SqlSession還提供了查找Mapper接口的有關(guān)方法。

每個(gè)線程都應(yīng)該有自己的SqlSession實(shí)例,因?yàn)檫@個(gè)實(shí)例不是線程安全的,所以它的最佳作用域是請(qǐng)求或方法作用域。

每次收到一個(gè)HTTP請(qǐng)求,就可以打開(kāi)一個(gè)SqlSession,返回了響應(yīng)之后就關(guān)閉它。

第四個(gè)就是我們編碼的主角Mapper接口:

Mapper接口是指程序員自行定義的一個(gè)數(shù)據(jù)操縱接口,類似于通常所說(shuō)的DAO接口。

跟DAO接口不同的地方在于Mapper接口只需要定義不需要實(shí)現(xiàn),mybatis會(huì)自動(dòng)為Mapper接口創(chuàng)建動(dòng)態(tài)代理對(duì)象。

Mapper接口的方法通常與Mapper配置文件中的select、insert、update和delete等XML節(jié)點(diǎn)存在一一對(duì)應(yīng)關(guān)系。

面試官:那你能說(shuō)下mybatis源碼中的主要部件嗎?

我:好的,主要部件如下:

1、SqlSession:作為mybatis工作的主要頂層API,表示和數(shù)據(jù)庫(kù)交互的會(huì)話,完成必要的數(shù)據(jù)庫(kù)增刪改查功能。

2、Executor:mybatis執(zhí)行器,是Mybatis調(diào)度的核心,負(fù)責(zé)SQL語(yǔ)句的生成和查詢緩存的維護(hù)。

3、StatementHandler:封裝了JDBCStatement操作,負(fù)責(zé)對(duì)JDBC Statement的操作。

4、ParameterHandler:負(fù)責(zé)對(duì)用戶傳遞的參數(shù)轉(zhuǎn)換成JDBC Statement所需要的參數(shù)。

5、ResultSetHandler:負(fù)責(zé)將JDBC返回的ResultSet結(jié)果集轉(zhuǎn)換成List類型的集合。

6、TypeHandler:負(fù)責(zé)Java數(shù)據(jù)類型和jdbc數(shù)據(jù)類型之間的映射和轉(zhuǎn)換。

7、MappedStatement:維護(hù)了一條select/update/delete/insert節(jié)點(diǎn)的封裝。

8、Sqlsource:負(fù)責(zé)根據(jù)用戶傳遞的parameterObject,動(dòng)態(tài)生成SQL語(yǔ)句,將信息封裝在BoundSql對(duì)象中,并返回。

9、BoundSql:表示動(dòng)態(tài)生成的SQL語(yǔ)句以及相應(yīng)的參數(shù)信息。

10、Configuration:Mybatis所有的配置信息都維護(hù)在這個(gè)對(duì)象中。

面試官:原理聊完了,接下來(lái)我們聊下實(shí)戰(zhàn)吧。你在項(xiàng)目中是怎么整合spring和mybatis的?

我:我先說(shuō)下xml的配置方式吧。

1、添加mybatis-spring的包:

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis-spring</artifactId>
  <version>x.x.x</version>
</dependency>

2、配置SqlSessionFactory:

整合后,可以不需要單獨(dú)的mybatis配置文件,全部的配置內(nèi)容可以再spring的上下文中。

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource"/>
  <!-- 當(dāng)mybatis的xml文件和mapper接口不在相同包下時(shí),需要用mapperLocations屬性指定xml文件的路徑。
         *是個(gè)通配符,代表所有的文件,**代表所有目錄下 -->
  <property name="mapperLocations" value="classpath:mapper/**/*.xml"/>
<!-- 加載mybatis的全局配置文件 -->
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml" />
</bean>

datasource:是數(shù)據(jù)源配置,常用的有DBCP,C3P0,Druid等。

mapperLocations:是指接口xml的文件配置,如果不配置的話映射接口類文件(mapper接口)和映射xml文件(mapper.xml)需要放在相同的包下。

3、配置數(shù)據(jù)映射器類:

利用mybatis-spring提供的自動(dòng)掃描機(jī)制:

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"
  xsi:schemaLocation="
  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd">
 
 <!-- 自動(dòng)掃描 -->
  <mybatis:scan base-package="org.mybatis.spring.sample.mapper" />
?
</beans>

我:(接著說(shuō))現(xiàn)在好像大多使用的是注解配置mybatis和數(shù)據(jù)源的方式,也就是使用java代碼和spring提供的注解。(其實(shí)步驟大致差不多,由于涉及安全問(wèn)題代碼不透露,想學(xué)習(xí)的可以網(wǎng)上找。)

面試官:你能寫(xiě)一個(gè)mapper映射文件中select的sql語(yǔ)句嗎?

我:隨手寫(xiě)了一個(gè),接著解釋到:這個(gè)語(yǔ)句被稱作selectPerson,接收一個(gè)int類型的參數(shù),并返回一個(gè)HashMap類型的對(duì)象,其中的鍵是列名,值便是結(jié)果行中的對(duì)應(yīng)值。

<select id="selectPerson" parameterType = "int" resultType="hashmap"
select * from person where id =#{id}
</select>

我(接著說(shuō)):select中有這些屬性可選:

  1. id:必選的,命名空間中唯一的標(biāo)識(shí)符,可以被用來(lái)引用這條語(yǔ)句。

  2. parameterType:可選,將會(huì)傳入這條語(yǔ)句的參數(shù)類的完全限定名或別名。

  3. resultType:從這條語(yǔ)句返回的期望類型的類的完全限定名或別名。

如果是集合,那應(yīng)該是集合包含的類型,而不是集合本身。

  1. resultMap:外部resultMap的命名引用。注意使用resultType或resultMap,不能同時(shí)使用。

  2. flushCache:默認(rèn)false。設(shè)置為true表示只要語(yǔ)句被調(diào)用,都會(huì)導(dǎo)致本地緩存和二級(jí)緩存被清空。

  3. useCache:對(duì)select元素為true。設(shè)置為true會(huì)導(dǎo)致本條語(yǔ)句的結(jié)果被二級(jí)緩存。

  4. timeout:默認(rèn)值為unset(依賴驅(qū)動(dòng))。這個(gè)設(shè)置是在拋出異常之前,驅(qū)動(dòng)程序等待數(shù)據(jù)庫(kù)返回請(qǐng)求結(jié)果的秒數(shù)。

  5. fetchSize:默認(rèn)值為unset(依賴驅(qū)動(dòng))。這是嘗試影響驅(qū)動(dòng)程序每次批量返回的結(jié)果行數(shù)和這個(gè)設(shè)置值相等。

  6. statementType:默認(rèn)值PREPARED。這會(huì)讓mybatis分別使用Statement,PreparedStatement或CallableStatement。

面試官:當(dāng)實(shí)體類中的屬性名和表中的字段名不一樣,應(yīng)該怎么辦?

我:有兩種方法。

第一種比較簡(jiǎn)單粗暴:通過(guò)在sql語(yǔ)句中定義別名,強(qiáng)行讓返回的字段名的的別名和實(shí)體類中的屬性名一致。

<select id="getByOrderId" parameterType="java.lang.Long" resultType="com.demo.entity.OrderInfo">
select order_id OrderId, order_sn orderSn, total_fee totalFee, create_time createTime
from order_info where order_id=#{orderId}
</select>

第二種比較優(yōu)雅:

通過(guò)resultMap來(lái)映射數(shù)據(jù)表的字段名和實(shí)體類的屬性名之間的對(duì)應(yīng)關(guān)系。

(推薦)

<resultMap id = "BaseResultMap" type="com.demo.entity.OrderInfo">
    <id property="OrderId" column="order_id"/>
    <result property="orderSn" column="order_sn"/>
    <result property="totalFee" column="total_fee"/>
    <result property="createTime" column="create_time"/>
</resultMap>
<select id="getByOrderId" parameterType="java.lang.Long" resultMap="BaseResultMap">
select order_id, order_sn, total_fee, create_time
from order_info where order_id=#{orderId}
</select>

面試官:如何獲取自動(dòng)生成的主鍵?

我:一般我們插入數(shù)據(jù)的話,如果想要知道剛剛插入的數(shù)據(jù)的主鍵是多少,可以通過(guò)以下方式來(lái)獲取。

通過(guò)LAST_INSERT_ID()獲取剛插入記錄的自增主鍵值,在insert語(yǔ)句執(zhí)行之后,執(zhí)行select LAST_INSERT_ID()就可以獲取自增主鍵。

<insert id='insert' parameterType="com.demo.entity.OrderInfo"    
<selectKey keyProperty="orderId" order="AFTER" resultType="java.lang.Long">        
select LAST_INSERT_ID()    
</selectKey>    
insert into order_info(order_sn,total_fee,create_time)    
values(#{orderSn},#{totalFee},#{createTime)</insert>

面試官:你知道m(xù)ybatis的哪些動(dòng)態(tài)sql?

我:

if:做條件判斷的,如果不使用這個(gè)標(biāo)簽,肯定要在代碼中做判斷,比如元素是否為空,字符串是否是空字符串,還比如一些特定的枚舉值需要判斷執(zhí)行條件。

choose/when/otherwise:這個(gè)標(biāo)簽組合類似于if/else if.../else,就是多個(gè)選項(xiàng)中選擇一個(gè),如果都不滿足條件,那只能執(zhí)行中的內(nèi)容了。

例如:

<select id="getStudentListChoose" parameterType="Student" resultMap="BaseResultMap">
    SELECT * from STUDENT WHERE 1=1
    <where>
        <choose>
            <when test="Name!=null and student!='' ">
                AND name LIKE CONCAT(CONCAT('%', #{student}),'%')
            </when>
            <when test="hobby!= null and hobby!= '' ">
                AND hobby = #{hobby}
            </when>
            <otherwise>
                AND AGE = 15
            </otherwise>
        </choose>
    </where>
</select>

3.foreach標(biāo)簽:用于循環(huán)。例如:

<select id="listByOrderIds" resultMap="BaseResultMap">
    select * from order_info where order_id in 
    <foreach collection="list" item="item" open="(" close=")" separator=",">
        #{item}
    </foreach>
</select>

4.另外還有set標(biāo)簽,where標(biāo)簽,trim標(biāo)簽等。

面試官:#{}和${}的區(qū)別是什么?

我:#{}是解析傳進(jìn)來(lái)的參數(shù),而另一個(gè)是拼接參數(shù)到SQl中。#{}是預(yù)編譯處理,而另一個(gè)是字符串替換。而且#{}可以防止SQL注入。

例如:select * from emp where name=#{empName},參數(shù)傳入empName->Smith,解析執(zhí)行后的SQL是:select * from emp where name=?。但是對(duì)于select * from emp where name=${empName},參數(shù)傳入empName->Smith,解析執(zhí)行后的SQL是:select * from emp where name='Smith'。

面試官:在mapper中如何傳遞多個(gè)參數(shù)?

我:有兩種方法:

1、使用占位符的思想:

(1)在映射文件中使用#{0},#{1}代表傳遞進(jìn)來(lái)的第幾個(gè)參數(shù)。

(2)使用@param注解來(lái)命名參數(shù)(推薦使用) 例如:

//mapper接口
public OrderInfo getByOrderIdAndStatus(Long orderId, String status);
?
//mapper.xml文件
<select id="getByOrderIdAndStatus" resultMap="BaseResultMap">
    select * from order_info where order_id=#{0} and status=#{1}
</select>
//mapper接口
public OrderInfo getByOrderIdAndStatus(@param("orderId")Long orderId, @param("status")String status);
?
//mapper.xml文件
<select id="getByOrderIdAndStatus" resultMap="BaseResultMap">
    select * from order_info where order_id=#{orderId} and status=#{status}
</select>

2、使用Map集合作為參數(shù)來(lái)裝載

Map<String, Object> map = new HashMap();
map.put("orderId", 1L);
map.put("status", "NORMAL");
OrderInfo orderinfo = getByOrderIdAndStatus(map);
?
//mapper接口
public OrderInfo getByOrderIdAndStatus(Map<String, Object> map);
?
//mapper.xml文件
<select id="getByOrderIdAndStatus" parameterType="map" resultMap="BaseResultMap">
    select * from order_info where order_id=#{orderId} and status=#{status}
</select>

面試官:不錯(cuò),看來(lái)你對(duì)mybatis運(yùn)用的挺熟練的了。今天的面試先到這里了,回家等消息吧。

我:好的。

心里有點(diǎn)忐忑,你們覺(jué)得我面試能過(guò)嗎?

文源網(wǎng)絡(luò),僅供學(xué)習(xí)之用,如有侵權(quán),聯(lián)系刪除。

我將優(yōu)質(zhì)的技術(shù)文章和經(jīng)驗(yàn)總結(jié)都匯集在了我的公眾號(hào)【Java圈子】里。

為方便大家學(xué)習(xí),我整理了一套學(xué)習(xí)資料,涵蓋Java虛擬機(jī)、spring框架、Java線程、數(shù)據(jù)結(jié)構(gòu)、設(shè)計(jì)模式等等,免費(fèi)提供給熱愛(ài)Java的同學(xué)!

file
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,382評(píng)論 3 415
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事?!?“怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,038評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,853評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,616評(píng)論 6 408
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,112評(píng)論 1 323
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,355評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,869評(píng)論 1 334
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,727評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,928評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,165評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,570評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,813評(píng)論 1 282
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,585評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,892評(píng)論 2 372

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