Hibernate 和 JPA主鍵生成策略

主鍵生成策略目錄.png
主鍵生成策略.png

1、native-重點

native由hibernate根據使用的數據庫自行判斷采用identity、hilo、sequence其中一種作為主鍵生成方式,靈活性很強。如果能支持identity則使用identity,如果支持sequence則使用sequence。

數據庫ID必須設置為自動增長列,不能手動賦值(數據類型必須是int類型);當數據庫為int類型時,最好使用主鍵類型為native(能夠跨數據庫)

<id name="id" column="id">
    <!--MySQL使用identity(id主鍵需要設置自增),Oracle使用sequence(hibernate默認查找hibernate_sequence序列,如果沒有需要自己創建)-->
    <generator class="native" />
</id>

例如MySQL使用identity,Oracle使用sequence

MySQL使用identity: id主鍵必須自增類型

id INT UNSIGNED AUTO_INCREMENT

注意:如果Hibernate自動選擇sequence或者hilo,則所有的表的主鍵都會從Hibernate默認的sequence或hilo表中取。并且,有的數據庫對于默認情況主鍵生成測試的支持,效率并不是很高。

使用sequence或hilo時,可以加入參數,指定sequence名稱或hi值表名稱等,如

<id name="id" column="id" type="int">
    <!--根據數據庫自動選擇identity、hilo、sequence其中一種,例如MySQL使用identity,Oracle使用sequence(默認序列查找hibernate_sequence序列),使用自定義序列時需加入參數sequence_name-->
    <generator class="native">
        <!--SEQ_MY_HIBERNATE 是自定義創建的序列-->
        <param name="sequence_name">SEQ_MY_HIBERNATE</param>
    </generator>
</id>

oracle創建序列

--oracle創建序列語句

--創建序列 SEQ_MY_HIBERNATE
create sequence SEQ_MY_HIBERNATE
minvalue 1
maxvalue 9999999999999999999999999999
start with 1
increment by 1
cache 20;

--創建序列 hibernate_sequence
create sequence hibernate_sequence
minvalue 1
maxvalue 9999999999999999999999999999
start with 1
increment by 1
cache 20;

特點:根據數據庫自動選擇,項目中如果用到多個數據庫時,可以使用這種方式,使用時需要設置表的自增字段或建立序列,建立表等。

2、increment-重點

由Hibernate從數據庫中取出主鍵的最大值(每個session只取1次),以該值為基礎,每次增量為1,在內存中生成主鍵,不依賴于底層的數據庫,因此可以跨數據庫。

數據庫ID可不設置為自動增長列,不能手動賦值(數據類型必須為int類型);

<id name="id" column="id" type="int">
    <!--在內存中生成主鍵,不依賴于底層的數據庫,因此可以跨數據庫,首次從數據庫取主鍵最大的值-->
    <generator class="increment" />
</id>

Hibernate調用org.hibernate.id.IncrementGenerator類里面的generate()方法,使用 select max(idColumnName) from tableName 語句獲取主鍵最大值。該方法被聲明成了synchronized,所以在一個獨立的Java虛擬機內部是沒有問題的,然而,在多個JVM同時并發訪問數據庫select max時就可能取出相同的值,再insert就會發生Dumplicate entry的錯誤。所以只能有一個Hibernate應用進程訪問數據庫,否則就可能產生主鍵沖突,所以不適合多進程并發更新數據庫,適合單一進程訪問數據庫,不能用于群集環境。

官方文檔:只有在沒有其他進程往同一張表中插入數據時才能使用,在集群下不要使用。

特點:跨數據庫,不適合多進程并發更新數據庫,適合單一進程訪問數據庫,不能用于群集環境。

3、sequence-重點

采用數據庫提供的sequence機制生成主鍵,需要數據庫支持sequence。如oralce、DB、SAP DB、PostgerSQL、McKoi中的sequence。MySQL這種不支持sequence的數據庫則不行(可以使用identity)。

采用數據庫提供的sequence機制生成主鍵。MySql數據庫不支持。(數據類型必須是int類型)。

<id name="id" column="id" type="int">
    <!--使用sequence,hibernate默認查找hibernate_sequence序列,如果沒有需要自己創建序列-->
    <generator class="sequence">
        <!--SEQ_MY_HIBERNATE 是自定義創建的序列,指定sequence的名稱-->
        <param name="sequence_name">SEQ_MY_HIBERNATE</param>
    </generator>
</id>

oracle創建序列

--oracle創建序列語句

--創建序列 SEQ_MY_HIBERNATE
create sequence SEQ_MY_HIBERNATE
minvalue 1
maxvalue 9999999999999999999999999999
start with 1
increment by 1
cache 20;

--創建序列 hibernate_sequence
create sequence hibernate_sequence
minvalue 1
maxvalue 9999999999999999999999999999
start with 1
increment by 1
cache 20;

Hibernate生成主鍵時,查找sequence并賦給主鍵值,主鍵值由數據庫生成,Hibernate不負責維護,使用時必須先創建一個sequence,如果不指定sequence名稱,則使用Hibernate默認的sequence,名稱為hibernate_sequence,前提要在數據庫中創建該sequence。

特點:只能在支持序列的數據庫中使用,如Oracle。

4、identity-重點

identity由底層數據庫生成標識符。identity是由數據庫自己生成的,但這個主鍵必須設置為自增長,使用identity的前提條件是底層數據庫支持自動增長字段類型,如DB2、SQL Server、MySQL、Sybase和HypersonicSQL等,Oracle這類沒有自增字段的則不支持。

數據庫ID必須設置為自動增長列,不能手動賦值(數據類型必須為int類型)

<id name="id" column="id">
    <generator class="identity" />
</id>

例:如果使用MySQL數據庫,則主鍵字段必須設置成auto_increment。

id int(11) primary key auto_increment

特點:只能用在支持自動增長的字段數據庫中使用,如MySQL。

5、uuid-掌握

UUID:Universally Unique Identifier,是指在一臺機器上生成的數字,它保證對在同一時空中的所有機器都是唯一的。按照開放軟件基金會(OSF)制定的標準計算,用到了以太網卡地址、納秒級時間、芯片ID碼和許多可能的數字,標準的UUID格式為:

xxxxxxxx-xxxx-xxxx-xxxxxx-xxxxxxxxxx (8-4-4-4-12)

其中每個 x 是 0-9 或 a-f 范圍內的一個十六進制的數字。

數據庫ID不能設置為自動增長列,不能手動賦值(數據類型必須是String類型);生成的是一個16進制的數字(不能跨數據庫)。

<id name="id" column="id">
    <generator class="uuid" />
</id>

Hibernate在保存對象時,生成一個UUID字符串作為主鍵,保證了唯一性,但其并無任何業務邏輯意義,只能作為主鍵,唯一缺點長度較大,32位(Hibernate將UUID中間的“-”刪除了)的字符串,占用存儲空間大,但是有兩個很重要的優點,Hibernate在維護主鍵時,不用去數據庫查詢,從而提高效率,而且它是跨數據庫的,以后切換數據庫極其方便。

特點:uuid長度大,占用空間大,跨數據庫,不用訪問數據庫就生成主鍵值,所以效率高且能保證唯一性,移植非常方便,推薦使用。

6、guid-掌握

GUID:Globally Unique Identifier全球唯一標識符,也稱作 UUID,是一個128位長的數字,用16進制表示。算法的核心思想是結合機器的網卡、當地時間、一個隨即數來生成GUID。從理論上講,如果一臺機器每秒產生10000000個GUID,則可以保證(概率意義上)3240年不重復。

數據庫ID不能設置為自動增長列,不能手動賦值(數據類型必須是String類型);
當數據庫為String類型時,最好使用主鍵類型為guid。

<id name="id" column="id">
    <generator class="guid" />
</id>

Hibernate在維護主鍵時,先查詢數據庫,獲得一個uuid字符串,該字符串就是主鍵值,該值唯一,缺點長度較大,支持數據庫有限,優點同uuid,跨數據庫,但是仍然需要訪問數據庫。

注意:長度因數據庫不同而不同

MySQL中使用select uuid()語句獲得的為36位(包含標準格式的“-”)

Oracle中,使用select rawtohex(sys_guid()) from dual語句獲得的為32位(不包含“-”)

特點:需要數據庫支持查詢uuid,生成時需要查詢數據庫,效率沒有uuid高,推薦使用uuid。

7、assigned-掌握

主鍵由外部程序負責生成,在 save() 之前必須指定一個。Hibernate不負責維護主鍵生成。與Hibernate和底層數據庫都無關,可以跨數據庫。在存儲對象前,必須要使用主鍵的setter方法給主鍵賦值,至于這個值怎么生成,完全由自己決定,這種方法應該盡量避免。

數據庫ID設為自動增長列時,在存儲對象前,主鍵可手動賦值,也可不手動賦值; 不賦值執行數據庫自動增長,賦值執行賦予的值(數據類型為int)。

<id name="id" column="id">
    <generator class="assigned" />
</id>

特點:可以跨數據庫,人為控制主鍵生成,應盡量避免。

8、hilo-掌握

hilo(高低位方式high low)是hibernate中最常用的一種生成方式,需要一張額外的表保存hi的值。保存hi值的表至少有一條記錄(只與第一條記錄有關),否則會出現錯誤。可以跨數據庫。

<id name="id" column="id">
    <generator class="hilo">
        <!--指定保存hi值的表名-->
        <param name="table">hibernate_hilo</param>
        <!--指定保存hi值的列名-->
        <param name="column">next_hi</param>
        <!--指定低位的最大值-->
        <param name="max_lo">100</param>
    </generator>
</id>

也可以省略table和column配置,其默認的表為hibernate_unique_key,列為next_hi

<id name="id" column="id">
    <generator class="hilo">
        <param name="max_lo">100</param>
    </generator>
</id>

hilo生成器生成主鍵的過程(以hibernate_hilo表,next_hi列為例):

  1. 獲得hi值:讀取并記錄數據庫的hibernate_hilo表中next_hi字段的值,數據庫中此字段值加1保存。

  2. 獲得lo值:從0到max_lo循環取值,差值為1,當值為max_lo值時,重新獲取hi值,然后lo值繼續從0到max_lo循環。

  3. 根據公式 hi * (max_lo + 1) 計算生成主鍵值。

注意:當hi值是0的時候,那么第一個值不是0*(max_lo+1)+0=0,而是lo跳過0從1開始,直接是1、2、3……

那max_lo配置多大合適呢?

這要根據具體情況而定,如果系統一般不重啟,而且需要用此表建立大量的主鍵,可以吧max_lo配置大一點,這樣可以減少讀取數據表的次數,提高效率;反之,如果服務器經常重啟,可以吧max_lo配置小一點,可以避免每次重啟主鍵之間的間隔太大,造成主鍵值主鍵不連貫。

特點:跨數據庫,hilo算法生成的標志只能在一個數據庫中保證唯一。

9、seqhilo-掌握

與hilo類似,通過hi/lo算法實現的主鍵生成機制,只是將hilo中的數據表換成了序列sequence,需要數據庫中先創建sequence,適用于支持sequence的數據庫,如Oracle。

<id name="id" column="id">
    <generator class="seqhilo">
        <param name="sequence">hibernate_seq</param>
        <param name="max_lo">100</param>
    </generator>
</id>

特點:與hilo類似,只能在支持序列的數據庫中使用。

10、foreign

使用另外一個相關聯的對象的主鍵作為該對象主鍵。主要用于一對一關系中。

<id name="id" column="id">
    <generator class="foreign">
        <param name="property">user</param>
    </generator>
</id>

<one-to-one name="user" class="domain.User" constrained="true" />

該例使用domain.User的主鍵作為本類映射的主鍵。

特點:很少使用,大多用在一對一關系中。

11、select

使用觸發器生成主鍵,主要用于早期的數據庫主鍵生成機制,能用到的地方非常少

12、自定義主鍵生成器

創建主鍵生成器類,實現 org.hibernate.id.IdentifierGenerator 接口

示例1:讀取數據庫信息來實現自定義主鍵生成器(缺點:查詢了數據庫表中的所有數據,讀取速度慢):

public class MyGenerator implements IdentifierGenerator {
 
    @Override
    public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
        Configuration configuration = new Configuration().configure();
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session2 = sessionFactory.openSession();
        Transaction transaction = session2.beginTransaction();
        // 得到數據庫集合
        List<Userinfo> lu = session2.createCriteria(Userinfo.class).list();
        String str = "";
        if (lu.size() > 0) {
            for (int i = 0; i < lu.size(); i++) {
                str = "Chain_0" + (i + 2);
            }
        } else {
            str = "Chain_01";
        }
        transaction.commit();
        session2.close();
        sessionFactory.close();
        return str;
    }
 
}

示例2:讀取數據庫信息來實現自定義主鍵生成器(優點:對數據庫的表只查詢了一次,讀取速度相對于示例1較快):

public class MyGenerator implements IdentifierGenerator {
 
    @Override
    public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
 
        // 定義開始字符
        String frist = "Chain_";
        // 連接對象
        Connection connection = session.connection();
        try {
            // 數據庫sql語句:查詢表的總數據
            PreparedStatement ps = connection.prepareStatement("SELECT COUNT(*) AS nextval FROM userinfo");
            // 返回結果集
            ResultSet rs = ps.executeQuery();
            if (rs.next()) {
                // 得到查詢的值+1
                int id = rs.getInt("nextval") + 1;
                String code = frist + StringUtils.leftPad("" + id, 3, "0");
                return code;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

在hibernate.xml里面設置:

<id name="id" type="java.lang.String">
    <column name="ID" />
    <generator class="com.zja.hibernate.generator.MyGenerator" />
</id>

13、Hibernate jpa 主鍵策略

Hibernate的主鍵策略jpa都能使用,另外jpa自己也提供了四種主鍵生成策略。

在jpa中我們可以通過注解@GeneratedValue(strategy=GenerationType.IDENTITY)來設置主鍵生成策略,但是jpa中的主鍵生成策略有不完美的地方,那就是只能設置數值型主鍵的生成策略,而對于字符串類型的主鍵不能處理。但是jpa給我們了一個生成器,實現jpa規范的框架可以通過生成器設置主鍵生成策略。

jpa 通過注解的方式來配置主鍵生成策略:配置uuid的生成器,生成主鍵的時候則會按照此方式生成

@Id
@Column(name="cust_id")
@GenericGenerator(name="my_uuid",strategy="uuid")// 定義一個生成器
@GeneratedValue(generator="my_uuid")//指定生成器
private String custId;

JPA自己提供了四種的主鍵生成策略:

  • AUTO:主鍵由程序控制。
  • IDENTITY:主鍵由數據庫自動生成(主要是自動增長型)
  • SEQUENCE:根據底層數據庫的序列來生成主鍵,條件是數據庫支持序列。
  • TABLE:使用一個特定的數據庫表格來保存主鍵。
  1. AUTO

    默認的配置。如果不指定主鍵生成策略,默認為AUTO。

GenerationType.AUTO:把主鍵生成策略交給持久化引擎(persistence engine),持久化引擎會根據數據庫在以上三種主鍵生成策略中選擇其中一種。此種主鍵生成策略比較常用,由于JPA默認的生成策略就是GenerationType.AUTO,所以使用此種策略時.可以顯式的指定@GeneratedValue(strategy = GenerationType.AUTO)也可以直接@GeneratedValue。例如:

@Id  
@GeneratedValue 

@Id
@GeneratedValue(strategy = GenerationType.AUTO)

  1. IDENTITY

? 主鍵則由數據庫自動維護,使用起來很簡單。

GenerationType.IDENTITY:此種主鍵生成策略就是通常所說的主鍵自增長,數據庫在插入數據時,會自動給主鍵賦值,比如MYSQL可以在創建表時聲明"auto_increment" 來指定主鍵自增長。該策略在大部分數據庫中都提供了支持(指定方法或關鍵字可能不同),但還是有少數數據庫不支持,所以可移植性略差。使用自增長主鍵生成策略是只需要聲明strategy = GenerationType.IDENTITY即可。例如:

@Id  
@GeneratedValue(strategy = GenerationType.IDENTITY)  

  1. SEQUENCE

    Hibernate同時也對JPA進行了擴展,可以在 GeneratedValue 中指定 generator,然后用 GenericGenerator 指定策略來維護主鍵。

GenerationType.SEQUENCE:在某些數據庫中,不支持主鍵自增長,比如Oracle,其提供了一種叫做"序列(sequence)"的機制生成主鍵。此時,GenerationType.SEQUENCE就可以作為主鍵生成策略。該策略的不足之處正好與TABLE相反,由于只有部分數據庫(Oracle,PostgreSQL,DB2)支持序列對象,所以該策略一般不應用于其他數據庫。類似的,該策略一般與另外一個注解一起使用@SequenceGenerator,@SequenceGenerator注解指定了生成主鍵的序列.然后JPA會根據注解內容創建一個序列(或使用一個現有的序列)。如果不指定序列,則會自動生成一個序列SEQ_GEN_SEQUENCE。例如:

@Id  
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "id_sequence")  
@SequenceGenerator(name = "id_sequence", initialValue = 1, allocationSize = 1, sequenceName = "ID_SEQUENCE")  
private int id;

  1. TABLE

GenerationType.TABLE:使用一個特定的數據庫表格來保存主鍵,持久化引擎通過關系數據庫的一張特定的表格來生成主鍵,這種策略的好處就是不依賴于外部環境和數據庫的具體實現,在不同數據庫間可以很容易的進行移植,但由于其不能充分利用數據庫的特性,所以不會優先使用。該策略一般與另外一個注解一起使用@TableGenerator,@TableGenerator注解指定了生成主鍵的表(可以在實體類上指定也可以在主鍵字段或屬性上指定),然后JPA將會根據注解內容自動生成一張表作為序列表(或使用現有的序列表)。如果不指定序列表,則會生成一張默認的序列表,表中的列名也是自動生成,數據庫上會生成一張名為sequence的表(SEQ_NAME,SEQ_COUNT)。序列表一般只包含兩個字段:第一個字段是該生成策略的名稱,第二個字段是該關系表的最大序號,它會隨著數據的插入逐漸累加。例如:

@Id  
@GeneratedValue(strategy = GenerationType.TABLE, generator = "id_sequence")  
@TableGenerator(name = "id_sequence", allocationSize = 1, table = "sequence_table", pkColumnName = "sequence_max_id", valueColumnName = "sequence_count")  
private int id;

補充說明:

@GeneratedValue: 給實體類生成唯一標識的主鍵(JPA要求實體Entity,必須有且只有一個主鍵)。有兩個屬性,分別是strategy和generator。
  generator:默認為空字符串,定義了主鍵生成器的名稱,對應的生成器有兩個:對應于同名的主鍵生成器@SequenceGenerator和@TableGenerator。
  strategy:一共有四種,被定義在枚舉類GenerationType中,包括:TABLE, SEQUENCE, IDENTITY 和AUTO。

@GenericGenerator: ** 是HIbernate提供的自定義主鍵策略生成器,需要和@GeneratedValue**一起使用,它的name屬性要和@GeneratedValue中的generator名稱要一致。支持13種策略。

@Id
@GeneratedValue(generator = "myGenerator")    
@GenericGenerator(name = "myGenerator", strategy = "uuid")

其中 strategy 有15個選項(13種策略),分別是

public DefaultIdentifierGeneratorFactory() {
    //uuid2特點是:不需要和數據庫交互,可根據RFC4122定義的5中變量控制具體的生成策略(因為符合RFC4122定義,所以避免了警告信息)
    register("uuid2", UUIDGenerator.class);
    //guid特點是:需要和數據庫進行一次查詢才能生成。數據庫全局唯一。MySQL 用 select uuid();Oracle 用 return "select rawtohex(sys_guid()) from dual"; 
    register("guid", GUIDGenerator.class);
    //uuid特點:不需要和數據庫交互,全網唯一。它會根據內部程序計算出32位長度的唯一id
    register("uuid", UUIDHexGenerator.class);
    register("uuid.hex", UUIDHexGenerator.class);
    //hilo特點:需要和數據庫交互,全數據庫唯一,與guid不同的是,在標識符的單個源必須被多個插入訪問時可以避免擁堵。
    register("hilo", TableHiLoGenerator.class);
    //assigned特點:不需要和數據庫交互,自己管理主鍵生成,顯示的指定id。沒有生成邏輯,如果為空就拋出異常。
    register("assigned", Assigned.class);
    //identity特點:需要和數據庫交互,數據插入后返回(反查)id,同一列唯一。
    register("identity", IdentityGenerator.class);
    //select特點:需要和數據庫交互。具有和identity類似的行為,有數據庫觸發器生成。
    register("select", SelectGenerator.class);
    //sequence特點:需要和數據庫交互(但不是每次都是)。sequence唯一。通過不同的數據庫,獲取不同的取值語句 dialect.getSequenceNextValString(sequenceName); 然后進行查詢,緩存到IntegralDataTypeHolder中,通過 generateHolder( session ).makeValue();進行獲得.
    register("sequence", SequenceGenerator.class);
    //seqhilo特點:需要和數據庫交互,全數據庫唯一,與guid不同的是,在標識符的單個源必須被多個插入訪問時可以避免擁堵。處理邏輯和 hilo 相同,只不過是使用一個具名的數據庫序列來生成高值部分
    register("seqhilo", SequenceHiLoGenerator.class);
    //increment特點:僅需要首次訪問數據庫。數據庫啟動時查詢表的最大主鍵列支,并通過 IntegralDataTypeHolder 緩存。插入一條,它自加一。不適合集群項目。
    register("increment", IncrementGenerator.class);
    //foreign特點:需要和數據庫訪問。通過給定的 entityName 和 propertyName 查詢獲得值
    register("foreign", ForeignGenerator.class);
    register("sequence-identity", SequenceIdentityGenerator.class);
    register("enhanced-sequence", SequenceStyleGenerator.class);
    register("enhanced-table", TableGenerator.class);
}

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,983評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,772評論 3 422
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,947評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,201評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,960評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,350評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,406評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,549評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,104評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,914評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,089評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,647評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,340評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,753評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,007評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,834評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,106評論 2 375