CascadeType.PERSIST 無(wú)法級(jí)聯(lián)保存數(shù)據(jù) 源碼級(jí)探究

前言

在業(yè)務(wù)開(kāi)發(fā)中泌绣,經(jīng)常遇到主鍵ID不能使用自增,而需要使用隨機(jī)字符串的情況预厌。但是在這種情況下阿迈,CascadeType.PERSIST級(jí)聯(lián)保存就有問(wèn)題了。這里我假設(shè)大家知道幾種CascadeType是什么意思轧叽。話(huà)不多提苗沧,開(kāi)始探究

背景

Parent表和Child表, 單向一對(duì)多關(guān)系@OneToMany

目的

保存Parent時(shí)級(jí)聯(lián)保存Child

Entity配置

  • Parent
@Getter //lombok,下同
@Setter
@Entity
public class Parent {

    @Id
    @Column(nullable = false, length = 32)
    private String id;

    //默認(rèn)的配置項(xiàng)不再重復(fù)寫(xiě)
    //例如OneToMany中的fetch默認(rèn)為FetchType.LAZY
    //JoinColum中的referencedColumnName默認(rèn)為Parent的主鍵
    @OneToMany(cascade = CascadeType.PERSIST)
    @JoinColumn(name = "parentId")
    private List<Child> childList;
}
  • Child
@Getter
@Setter
@Entity
public class Child {

    @Id
    @Column(nullable = false, length = 32)
    private String id;

    @Column(length = 32)
    private String parentId;
}

兩個(gè)表的主鍵ID都使用了String類(lèi)型炭晒。到此Entity寫(xiě)完了待逞,如果配置中的spring.jpa.hibernate.ddl-auto你設(shè)置為updatecreate的話(huà)啟動(dòng)應(yīng)用之后數(shù)據(jù)庫(kù)中就有如下兩個(gè)表了

image

image

測(cè)試級(jí)聯(lián)保存

public void create() {
    Parent parent = new Parent();
    parent.setId(RandomStringUtils.randomAlphabetic(32));

    List<Child> childList = new ArrayList<>();
    for (int i = 0; i < 5; i++) {
        Child child = new Child();
        child.setId(RandomStringUtils.randomAlphabetic(32));
        //不用設(shè)置parentId哦
        childList.add(child);
    }

    parent.setChildList(childList);
    parentRepo.save(parent);
}

代碼很簡(jiǎn)單,不解釋了网严。重頭戲要來(lái)了识樱,運(yùn)行!

org.springframework.orm.jpa.JpaObjectRetrievalFailureException: Unable to find com.sh.blog.entity.Child with id qfHfYhPxvwMEfadUFLLkuXwQGdUDsJCG; nested exception is javax.persistence.EntityNotFoundException: Unable to find com.sh.blog.entity.Child with id qfHfYhPxvwMEfadUFLLkuXwQGdUDsJCG

    at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:389)
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:246)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:525)
    at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59)
    at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:209)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
    at com.sun.proxy.$Proxy86.save(Unknown Source)
    at com.sh.blog.repository.ParentRepoTest.create(ParentRepoTest.java:37)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: javax.persistence.EntityNotFoundException: Unable to find com.sh.blog.entity.Child with id qfHfYhPxvwMEfadUFLLkuXwQGdUDsJCG
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$JpaEntityNotFoundDelegate.handleEntityNotFound(EntityManagerFactoryBuilderImpl.java:144)
    at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:227)
    at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:278)
    at org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:121)
    at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:89)
    at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1129)
    at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:1022)
    at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:639)
    at org.hibernate.type.EntityType.resolve(EntityType.java:431)
    at org.hibernate.type.EntityType.replace(EntityType.java:330)
    at org.hibernate.type.CollectionType.replaceElements(CollectionType.java:518)
    at org.hibernate.type.CollectionType.replace(CollectionType.java:663)
    at org.hibernate.type.AbstractType.replace(AbstractType.java:147)
    at org.hibernate.type.TypeHelper.replaceAssociations(TypeHelper.java:261)
    at org.hibernate.event.internal.DefaultMergeEventListener.copyValues(DefaultMergeEventListener.java:427)
    at org.hibernate.event.internal.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:240)
    at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:301)
    at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:170)
    at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:69)
    at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:840)
    at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:822)
    at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:827)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:1161)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:301)
    at com.sun.proxy.$Proxy84.merge(Unknown Source)
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:511)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:515)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:500)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:477)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:56)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
    ... 38 more

上面是全部的異常信息震束,顯示Unable to find com.sh.blog.entity.Child with id qfHfYhPxvwMEfadUFLLkuXwQGdUDsJCG怜庸,我們保存數(shù)據(jù)為啥她要去用idChild呢?神經(jīng)病吧垢村。于是一頓Google割疾,看CascadeType的文檔,看Hibernate的級(jí)聯(lián)操作的文檔嘉栓,看……一下午過(guò)去了杈曲,一晚上過(guò)去了驰凛,一上午過(guò)去了。次日中午我決定担扑,刨源碼!

到處打斷點(diǎn)跟了很多次代碼之后趣钱,我發(fā)現(xiàn)問(wèn)題所在了涌献。

首先看repositorysave方法,我繼承的是JpaRepository首有。

  1. save方法
@Transactional
public <S extends T> S save(S entity) {

    if (entityInformation.isNew(entity)) {
        em.persist(entity);
        return entity;
    } else {
        return em.merge(entity);
    }
}

咦燕垃?判斷entity是不是新的?什么鬼井联,繼續(xù)跟進(jìn)isNew方法

  1. isNew方法
public boolean isNew(T entity) {

    //取到ID值
    ID id = getId(entity);
    //取到ID字段的類(lèi)
    Class<ID> idType = getIdType();

    //判斷ID字段是不是原始類(lèi)
    if (!idType.isPrimitive()) {
        return id == null;
    }

    //判斷ID字段是否是Number的子類(lèi)
    if (id instanceof Number) {
        return ((Number) id).longValue() == 0L;
    }

    //不支持的類(lèi)型卜壕,拋異常
    throw new IllegalArgumentException(String.format("Unsupported primitive id type %s!", idType));
}

源碼我已經(jīng)注釋了,看到這里我說(shuō)一下她如何判斷一個(gè)entity是不是新的烙常。

首先轴捎,判斷entity的主鍵是不是原始類(lèi)型(怎么判斷我后面講)。如果不是原始類(lèi)型那就判斷主鍵值蚕脏,null就是新的侦副,不為null就是舊的(我們暫且這么說(shuō));然后驼鞭,如果主鍵是原始類(lèi)型的話(huà)秦驯,看是不是Number的子類(lèi),也就是判斷是不是數(shù)字挣棕,如果是就判斷主鍵值是否等于0译隘,0就是新的,不為0就是舊的洛心;最后固耘,拋異常,說(shuō)咱不支持這類(lèi)型~

那她如何判斷是否是原始類(lèi)型呢皂甘?看源碼

  1. isPrimitive方法
/**
    * Determines if the specified {@code Class} object represents a
    * primitive type.
    *
    * <p> There are nine predefined {@code Class} objects to represent
    * the eight primitive types and void.  These are created by the Java
    * Virtual Machine, and have the same names as the primitive types that
    * they represent, namely {@code boolean}, {@code byte},
    * {@code char}, {@code short}, {@code int},
    * {@code long}, {@code float}, and {@code double}.
    *
    * <p> These objects may only be accessed via the following public static
    * final variables, and are the only {@code Class} objects for which
    * this method returns {@code true}.
    *
    * @return true if and only if this class represents a primitive type
    *
    * @see     java.lang.Boolean#TYPE
    * @see     java.lang.Character#TYPE
    * @see     java.lang.Byte#TYPE
    * @see     java.lang.Short#TYPE
    * @see     java.lang.Integer#TYPE
    * @see     java.lang.Long#TYPE
    * @see     java.lang.Float#TYPE
    * @see     java.lang.Double#TYPE
    * @see     java.lang.Void#TYPE
    * @since JDK1.1
    */
public native boolean isPrimitive();

明白了吧玻驻。上面注釋說(shuō)的這幾種類(lèi)型就是原始類(lèi)型。

搞清楚如何判斷一個(gè)entity是否是新的偿枕,那我們回來(lái)看save方法的代碼

@Transactional
public <S extends T> S save(S entity) {

    if (entityInformation.isNew(entity)) {
        em.persist(entity);
        return entity;
    } else {
        return em.merge(entity);
    }
}

如果是entity是新的就用persist璧瞬,否則就用merge。那按照上面說(shuō)的方法渐夸,ParentChild的ID值是String嗤锉,不是原始類(lèi)型,然后我們又生成了一個(gè)隨機(jī)字符串主鍵墓塌,那顯然不是新的啊瘟忱,走的是merge操作奥额。靠访诱!我級(jí)聯(lián)PERSIST有毛用啊垫挨。那就換成MERGE

@Getter
@Setter
@Entity
public class Parent {
    @Id
    @Column(nullable = false, length = 32)
    private String id;

    @OneToMany(cascade = CascadeType.MERGE)
    @JoinColumn(name = "parentId")
    private List<Child> childList;
}

再次執(zhí)行!


success

數(shù)據(jù)庫(kù)的圖片我就不貼了触菜,正反是保存成功了九榔。

問(wèn)題解決了,但開(kāi)頭為啥設(shè)置成CascadeType.PERSIST進(jìn)行級(jí)聯(lián)保存的時(shí)候報(bào)那樣的錯(cuò)誤呢涡相?現(xiàn)在回頭想想既然執(zhí)行的是merge操作更新哲泊,那肯定是要先查一下數(shù)據(jù)庫(kù)再更新啊,沒(méi)有查到肯定報(bào)錯(cuò)了催蝗。

總結(jié)

如果你的數(shù)據(jù)表主鍵是String類(lèi)型并且程序自己生成隨機(jī)字符串填充切威,使用JpaRepositorysave方法保存數(shù)據(jù),那CascadeType.PERSIST就不是級(jí)聯(lián)保存了丙号,而是“級(jí)聯(lián)異诚入”了。需要換成CascadeType.MERGE槽袄,原因上面說(shuō)了烙无。

但是轉(zhuǎn)過(guò)頭來(lái)想,如果主鍵依然是String類(lèi)型遍尺,但不需要我們自己生成隨機(jī)字符串填充截酷,而是像自增主鍵那樣把這項(xiàng)任務(wù)交出去,那我們的entity就是新的乾戏,就可以使用CascadeType.PERSIST保存了迂苛。例如像下面這樣

@Getter
@Setter
@Entity
public class Parent {
    @Id
    @GeneratedValue(generator = "jpa-guid")
    @GenericGenerator(name = "jpa-guid", strategy = "guid")
    @Column(nullable = false, length = 36)
    private String id;

    //注意這里是PERSIST
    @OneToMany(cascade = CascadeType.PERSIST)
    @JoinColumn(name = "parentId")
    private List<Child> childList;
}

像上面這樣寫(xiě)的話(huà),就不用管ID生成了鼓择,像自增ID那樣直接保存就行三幻,ID會(huì)自動(dòng)生成guid碼填充(32位可裝不下哦),也不用使用CascadeType.MERGE了呐能,使用CascadeType.PERSIST級(jí)聯(lián)保存即可(Child的主鍵生成策略也同時(shí)需要改)念搬。

題外話(huà)

有些小伙伴可能看到了,我的Entity配置中寫(xiě)了@Getter@Setter注解摆出,用過(guò)lombok組件的都知道朗徊,但有些小伙伴說(shuō)了,你為啥不直接寫(xiě)成@Data呢偎漫?閑著沒(méi)事兒吧爷恳?不是,我的意思是盡量不要賦予程序用不著的權(quán)限象踊,也不要寫(xiě)程序用不著的方法温亲。就像這個(gè)問(wèn)題棚壁,如果一上手就寫(xiě)CascadeType.ALL,早就在家抱著媳婦兒喝咖啡了栈虚,但是如果寫(xiě)成CascadeType.ALL的話(huà)袖外,程序有時(shí)可能就不會(huì)按照你的意志執(zhí)行了,多了一些隱藏的bug魂务,而這些bug導(dǎo)致的結(jié)果可能會(huì)讓你抱著媳婦兒也寢食難安在刺!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市头镊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌魄幕,老刑警劉巖相艇,帶你破解...
    沈念sama閱讀 222,729評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異纯陨,居然都是意外死亡坛芽,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)翼抠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)咙轩,“玉大人,你說(shuō)我怎么就攤上這事阴颖』詈埃” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,461評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵量愧,是天一觀的道長(zhǎng)钾菊。 經(jīng)常有香客問(wèn)我,道長(zhǎng)偎肃,這世上最難降的妖魔是什么煞烫? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,135評(píng)論 1 300
  • 正文 為了忘掉前任扣蜻,我火速辦了婚禮懂缕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拂共。我一直安慰自己紊馏,他們只是感情好料饥,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著瘦棋,像睡著了一般稀火。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上赌朋,一...
    開(kāi)封第一講書(shū)人閱讀 52,736評(píng)論 1 312
  • 那天凰狞,我揣著相機(jī)與錄音篇裁,去河邊找鬼。 笑死赡若,一個(gè)胖子當(dāng)著我的面吹牛达布,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播逾冬,決...
    沈念sama閱讀 41,179評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼黍聂,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了身腻?” 一聲冷哼從身側(cè)響起产还,我...
    開(kāi)封第一講書(shū)人閱讀 40,124評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嘀趟,沒(méi)想到半個(gè)月后脐区,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,657評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡她按,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評(píng)論 3 342
  • 正文 我和宋清朗相戀三年牛隅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片酌泰。...
    茶點(diǎn)故事閱讀 40,872評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡媒佣,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出陵刹,到底是詐尸還是另有隱情默伍,我是刑警寧澤,帶...
    沈念sama閱讀 36,533評(píng)論 5 351
  • 正文 年R本政府宣布授霸,位于F島的核電站巡验,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏碘耳。R本人自食惡果不足惜显设,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望辛辨。 院中可真熱鬧捕捂,春花似錦、人聲如沸斗搞。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,700評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)僻焚。三九已至允悦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間虑啤,已是汗流浹背隙弛。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,819評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工架馋, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人全闷。 一個(gè)月前我還...
    沈念sama閱讀 49,304評(píng)論 3 379
  • 正文 我出身青樓叉寂,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親总珠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子屏鳍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評(píng)論 2 361

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