Hibernate之关系映射

一、单向关系之:一对多映射

一对多映射关系由one方(Department)来维护

  • many方:Employee
package com.revanwang.one2many;

import lombok.Data;

@Data
public class Employee {
    private Long    id;
    private String  name;
}
  • one方:Department
package com.revanwang.one2many;

import lombok.Data;

import java.util.ArrayList;
import java.util.List;

@Data
public class Department {

    private Long id;
    private String name;

    private List<Employee> employees = new ArrayList<>();

}
  • test
package com.revanwang.one2many;

import com.revanwang.util.HibernateUtil;
import org.hibernate.Session;
import org.junit.Test;

public class APP {

    @Test
    public void one2manyTest() {
        Employee e1 = new Employee();
        e1.setName("W");

        Employee e2 = new Employee();
        e2.setName("Y");

        Department d = new Department();
        d.setName("市场部");
        d.getEmployees().add(e1);
        d.getEmployees().add(e2);

        Session session = HibernateUtil.getHibernateSession();
        session.beginTransaction();
        session.persist(d);
        session.persist(e1);
        session.persist(e2);
        session.getTransaction().commit();
    }

}
  • One2Many.hbm.xml
<?xml version="1.0"?>
        <!DOCTYPE hibernate-mapping PUBLIC
                "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
                "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.revanwang.one2many">

    <!--many方-->
    <class name="Employee" table="t_employee">
        <id name="id">
            <generator class="native"></generator>
        </id>

        <property name="name"/>
    </class>

    <!--one方-->
    <class name="Department" table="t_department">
        <id name="id" column="id">
            <generator class="native"></generator>
        </id>

        <property name="name"/>

        <!-- Bag集合设置 -->
        <bag name="employees">
            <key column="depart_id"></key>
            <one-to-many class="Employee"/>
        </bag>
    </class>

</hibernate-mapping>

小结:

  • save方法:由Department来维护外键关系,所以得发额外的2条SQL
  • 在保存对象的时候,因为对象的关系有one方维护,所以在保存many的时候,不会去修改外键的值;只能在one方保存完成之后,由one方发送额外的update语句去修改many方的外键的值

二、单向关系之:多对一映射

多对一映射关系由many方(Employee)来维护

  • many方:Employee
package com.revanwang.many2one;

import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class Employee {
    private Long    id;
    private String  name;
    private Department department;

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", department=" + department +
                '}';
    }
}
  • one方:Department
package com.revanwang.many2one;

import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class Department {

    private Long id;
    private String name;

    @Override
    public String toString() {
        return "Department{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
  • many2oneTest
    public void many2oneTest() {
        Department d = new Department();
        d.setName("研发部");

        Employee e1 = new Employee();
        e1.setName("S");
        e1.setDepartment(d);

        Employee e2 = new Employee();
        e2.setName("s");
        e2.setDepartment(d);

        Session session = HibernateUtil.getHibernateSession();
        session.beginTransaction();

        session.persist(d);
        session.persist(e1);
        session.persist(e2);

        session.getTransaction().commit();
    }
  • Many2One.hbm.xml
<?xml version="1.0"?>
        <!DOCTYPE hibernate-mapping PUBLIC
                "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
                "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.revanwang.many2one">

    <!--many方-->
    <class name="Employee">
        <id name="id">
            <generator class="native"></generator>
        </id>

        <property name="name"/>
        
        <many-to-one name="department" column="depart_id"/>
    </class>

    <!--one方-->
    <class name="Department">
        <id name="id" column="id">
            <generator class="native"></generator>
        </id>

        <property name="name"/>
    </class>

</hibernate-mapping>

小结:
要先保存one方,在保存many方,否则会造成额外的SQL语句

三、双向关系之:多对一

  • one方(Department)
package com.revanwang.one2manyandmany2one;

import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;

@Setter
@Getter
public class Department {

    private Long id;
    private String name;

    private List<Employee> employees = new ArrayList<>();

}
  • many方(Employee)
package com.revanwang.one2manyandmany2one;

import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class Employee {
    private Long    id;
    private String  name;
    private Department department;
}
  • one2manyandmany2one.hbm.xml
<?xml version="1.0"?>
        <!DOCTYPE hibernate-mapping PUBLIC
                "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
                "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.revanwang.one2manyandmany2one">

    <!--many方-->
    <class name="Employee">
        <id name="id">
            <generator class="native"></generator>
        </id>

        <property name="name"/>
        <many-to-one name="department" column="depart_id"/>
    </class>

    <!--one方-->
    <class name="Department">
        <id name="id" column="id">
            <generator class="native"></generator>
        </id>

        <property name="name"/>

        <!-- Bag集合设置 -->
        <bag name="employees">
            <key column="department_id"></key>
            <one-to-many class="Employee"/>
        </bag>
    </class>

</hibernate-mapping>
  • test
    public void appTest() {
        Department d = new Department();
        d.setName("销售部");

        Employee e1 = new Employee();
        e1.setName("H");
        e1.setDepartment(d);

        Employee e2 = new Employee();
        e2.setName("h");
        e2.setDepartment(d);

        d.getEmployees().add(e1);
        d.getEmployees().add(e2);

        Session session = HibernateUtil.getHibernateSession();
        session.beginTransaction();

        session.persist(d);
        session.persist(e1);
        session.persist(e2);

        session.getTransaction().commit();

    }
  • db
    双向关系DB.png
  • SQL

Hibernate: 
    insert 
    into
        Department
        (name) 
    values
        (?)
Hibernate: 
    insert 
    into
        Employee
        (name, depart_id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        Employee
        (name, depart_id) 
    values
        (?, ?)
Hibernate: 
    update
        Employee 
    set
        department_id=? 
    where
        id=?
Hibernate: 
    update
        Employee 
    set
        department_id=? 
    where
        id=?

小结:因为先保存one方再保存many方,所以many方的外键(one方的主键)其实是已经确定的,所以不应该在发送update来更新Employee的外键,造成这样现象的原因是因为one方和many方都在维护双向的关系的原因,所以需要一方放弃维护关系,那么该由哪一方来放弃维护关系?由于外键是在many方显示的,所以many方来维护关系是最恰当的,所以one方来放弃关系的维护

  • 控制反转(inverse):inverse=true:表示己方不维护关系
<?xml version="1.0"?>
        <!DOCTYPE hibernate-mapping PUBLIC
                "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
                "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.revanwang.one2manyandmany2one">

    <!--many方-->
    <class name="Employee">
        <id name="id">
            <generator class="native"></generator>
        </id>

        <property name="name"/>
        <many-to-one name="department" column="depart_id"/>
    </class>

    <!--one方-->
    <class name="Department">
        <id name="id" column="id">
            <generator class="native"></generator>
        </id>

        <property name="name"/>

        <!-- Bag集合设置 -->
        <bag name="employees" inverse="true">
            <key column="department_id"></key>
            <one-to-many class="Employee"/>
        </bag>
    </class>

</hibernate-mapping>
  • inverse=true时DB
    inverseDB.png
  • SQL
Hibernate: 
    insert 
    into
        Department
        (name) 
    values
        (?)
Hibernate: 
    insert 
    into
        Employee
        (name, depart_id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        Employee
        (name, depart_id) 
    values
        (?, ?)

小结:

  • 1、one方inverse=true时,发送SQL时在没有执行update了,减少了SQL语句发送
  • 2、在映射一对多的双向关联关系时,应该在one方把<set>/<list>/<bag>元素的inverse属性设置为true,提高性感
  • 3、在建立两个对象的双向关联时,应该同时修改两端对象的相应属性
  • 4、当删除双向的关联关系时,也应该修改两端对象的相应属性

四、关系映射之:多对多关系映射

  • Student
package com.revanwang.many2many;

import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;

@Setter
@Getter
public class Student {

    private Long    id;
    private String  name;

    private List<Teacher> teachers = new ArrayList<>();

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
  • Teacher
package com.revanwang.many2many;

import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;

@Setter
@Getter
public class Teacher {
    private Long    id;
    private String  name;

    private List<Student> students = new ArrayList<>();

    @Override
    public String toString() {
        return "Teacher{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", students=" + students +
                '}';
    }
}
  • APPTest
package com.revanwang.many2many;

import com.revanwang.util.HibernateUtil;
import org.hibernate.Session;
import org.junit.Before;
import org.junit.Test;

public class APP {

    @Before
    public void APPTest() {
        Student s1 = new Student();
        s1.setName("s1");

        Student s2 = new Student();
        s2.setName("s2");

        Teacher t1 = new Teacher();
        t1.setName("t1");

        Teacher t2 = new Teacher();
        t2.setName("t2");

        s1.getTeachers().add(t1);
        s1.getTeachers().add(t2);

        s2.getTeachers().add(t1);

        t1.getStudents().add(s1);
        t1.getStudents().add(s2);


        Session session = HibernateUtil.getHibernateSession();
        session.beginTransaction();

        session.persist(s1);
        session.persist(s2);

        session.persist(t1);
        session.persist(t2);

        session.getTransaction().commit();
    }


    @Test
    public void testGet() {
        Session session = HibernateUtil.getHibernateSession();
        session.beginTransaction();

        Teacher teacher = (Teacher) session.load(Teacher.class, 1L);

        session.getTransaction().commit();

        System.out.println(teacher);
    }

}
  • many2many.xml
<?xml version="1.0"?>
        <!DOCTYPE hibernate-mapping PUBLIC
                "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
                "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.revanwang.many2many">

    <!--student-->
    <class name="Student">
        <id name="id">
            <generator class="native"></generator>
        </id>
        <property name="name"/>

        <!--
            在配置集合时:
            1、table:中间表的名称
            2、key:在中间表中关联我的主键(Student表的主键)
            3、many-to-many:表示对象的关系
            4、class:对象类型
            5、column:在中间表中哪个列作为外键关联到对方的主键(Teacher表的主键)
        -->
        <bag name="teachers" table="teacher_student">
            <key column="s_id"></key>
            <many-to-many class="Teacher" column="t_id"/>
        </bag>

    </class>

    <!--Teacher-->
    <class name="Teacher">
        <id name="id">
            <generator class="native"></generator>
        </id>
        <property name="name"/>

        <bag name="students" table="teacher_student" inverse="true">
            <key column="t_id"/>
            <many-to-many class="Student" column="s_id"/>
        </bag>

    </class>

</hibernate-mapping>

小结:

  • 1、如果使用set集合,中间表会为两个外键创建一个复合主键;
  • 2、必须让一边放弃关系的维护,哪边在负责维护这个关系,就让对方放弃关系的管理(设计到页面上,哪个模块在添加另外一个对象,另外一个对象就放弃关系的管理)

五、关系映射之:组件关系映射

  • Address
package com.revanwang.component;

import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class Address {
    private String province;
    private String city;
    private String street;

    @Override
    public String toString() {
        return "Address{" +
                "province='" + province + '\'' +
                ", city='" + city + '\'' +
                ", street='" + street + '\'' +
                '}';
    }
}
  • Company
package com.revanwang.component;

import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class Company {
    private Long id;
    private String name;
    private Address address;
    private Address regAddress;

    @Override
    public String toString() {
        return "Company{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", address=" + address +
                ", regAddress=" + regAddress +
                '}';
    }
}
  • component.xml
<?xml version="1.0"?>
        <!DOCTYPE hibernate-mapping PUBLIC
                "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
                "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.revanwang.component">

    <class name="Company">
        <id name="id">
            <generator class="native"></generator>
        </id>
        
        <property name="name"/>
        
        <!--组件映射-->
        <component name="address" class="Address">
            <property name="province"/>
            <property name="city"/>
            <property name="street"/>
        </component>

        <component name="regAddress" class="Address">
            <property name="province" column="regProvince"/>
            <property name="city" column="regCity"/>
            <property name="street" column="regStreet"/>
        </component>

    </class>

</hibernate-mapping>
  • APPTest
package com.revanwang.component;

import com.revanwang.util.HibernateUtil;
import org.hibernate.Session;
import org.junit.Test;

public class APP {

    @Test
    public void APPTest() {
        Address address = new Address();
        address.setCity("杭州");
        address.setProvince("余杭区");
        address.setStreet("仓前");

        Address regAddress = new Address();
        regAddress.setCity("杭州_reg");
        regAddress.setProvince("余杭区_reg");
        regAddress.setStreet("仓前_reg");

        Company company = new Company();
        company.setName("Revan");
        company.setAddress(address);
        company.setRegAddress(regAddress);

        Session session = HibernateUtil.getHibernateSession();
        session.beginTransaction();

        session.persist(company);

        session.getTransaction().commit();
    }
}
  • component_DB


    component.png

六、继承映射

  • User
package com.revanwang.extend;

import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class User {
    private Long    id;
    private String  name;
}
  • Employee
package com.revanwang.extend;

import lombok.Getter;
import lombok.Setter;

import java.math.BigDecimal;

@Setter
@Getter
public class Employee extends User {
    private BigDecimal salary;
}
  • Customer
package com.revanwang.extend;

import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class Customer extends User {
    private String address;
}

6.1:继承关系生成一张表

  • extend_single.xml
<?xml version="1.0"?>
        <!DOCTYPE hibernate-mapping PUBLIC
                "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
                "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.revanwang.extend">

    <class name="User" discriminator-value="0">
        <id name="id">
            <generator class="native"></generator>
        </id>


        <!--
            设置用户类型的识别列:
            type=0:一般用户
            type=1:员工
            type=2:客户
        -->
        <discriminator column="type" type="int"/>
        <property name="name"/>
        <subclass name="Employee" discriminator-value="1">
            <property name="salary"/>
        </subclass>

        <subclass name="Customer" discriminator-value="2">
            <property name="address"/>
        </subclass>

    </class>

</hibernate-mapping>
  • APPTest
    public void APPTest() {
        User user = new User();
        user.setName("WRW");

        Employee employee = new Employee();
        employee.setName("Emp");
        employee.setSalary(new BigDecimal("10086"));

        Customer customer = new Customer();
        customer.setName("Customer");
        customer.setAddress("浙江省杭州市");

        Session session = HibernateUtil.getHibernateSession();
        session.beginTransaction();

        session.persist(user);
        session.persist(employee);
        session.persist(customer);

        session.getTransaction().commit();
    }

}
  • db
    extend_single.png

    小结:

  • 由于继承关系生成一张表时,所以需要使用一个标识来区别每个不同类型
  • load方法
    public void getTest() {
        Session session = HibernateUtil.getHibernateSession();
        session.beginTransaction();

        User user = (User) session.load(Employee.class, 2L);
        session.getTransaction().commit();
        System.out.println(user);
    }
  • SQL
    select
        employee0_.id as id1_0_0_,
        employee0_.name as name3_0_0_,
        employee0_.salary as salary4_0_0_ 
    from
        User employee0_ 
    where
        employee0_.id=? 
        and employee0_.type=1

发现SQL中where语句中多了一个type=1条件,如何判断type是什么(0、1、2),通过load(Employee.class, 2L)可知要查询的是Employee类型,在通过extend_single.xml文件可知,Employee类型的type值是1

6.2:每个具体类一张表

  • extend_union.xml
<?xml version="1.0"?>
        <!DOCTYPE hibernate-mapping PUBLIC
                "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
                "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.revanwang.extend">

    <class name="User">
        <id name="id">
            <generator class="org.hibernate.id.enhanced.TableGenerator"/>
        </id>

        <property name="name"/>

        <!--
            每个子类一张表:
            每个实体类属性都对应着一张表
            此时因为继承体系中所有实体类必须使用同一个主键
            因此,不能使用native生成策略
        -->
        <union-subclass name="Employee">
            <property name="salary"/>
        </union-subclass>

        <union-subclass name="Customer">
            <property name="address"/>
        </union-subclass>

    </class>

</hibernate-mapping>

6.3:每个子类一张表

  • extend_joined.xml
<?xml version="1.0"?>
        <!DOCTYPE hibernate-mapping PUBLIC
                "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
                "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.revanwang.extend">

    <class name="User">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name"/>

        <!--
            每个具体类一张表:
            将子类和父类相同的属性保存在父类表中,而子类增加的属性,只保存在子类表中
            <key column="/>:共享主键(即是主键又是外键)
        -->
        <joined-subclass name="Employee">
            <key column="employee_id"/>
            <property name="salary"/>
        </joined-subclass>

        <joined-subclass name="Customer">
            <key column="customer_id"/>
            <property name="address"/>
        </joined-subclass>

    </class>

</hibernate-mapping>

小结:

  • 1、继承关系生成一张表

    • 优点:支持多条查询,查询继承关系中的父类和子类数据时只需要一次简单的查询即可查询相应的数据。性能最高
    • 缺点:需要添加额外列来区分子类,表中有很多列为null,不能为所有子类属性对应字段,设置为NOT NULL约束
  • 2、每个子类一张表

    • 优点:符合关系数据模型设计规则
    • 缺点:新增、查询需要操作多张表,性能不如继承关系一张表
  • 3、每个具体类一张表

    • 优点:实现继承体系最简单
    • 缺点:多态查询性能最低

七、组合关系映射

聚合关系

一般是由2个模块分别管理整体和部分的对象

组合关系

是一种强聚合关系,强调了整体和部分不能分开,一般把整体部分称之为主对象(父对象),把部分称之为从对象(子对象)
比如:销售订单(SaleBill)和销售订单明细(SaleBillltem)
组合关系的两个对象都是在同一个模块中管理的,都是在主对象中做管理,所以只需要设计SaleBillDAO,不需要设计SaleBillltemDAO,因为订单明细的CRUD都是在销售订单中完成的。

操作分析:

    增加:
        1):保存销售订单信息.
        2):保存销售订单明细信息.
    删除:
        1):删除销售订单明细信息.
        2):删除销售订单信息.
    修改:
        1):更新销售订单信息.
        2):保存新的销售订单明细.
        3):更新被修改过的销售订单明细信息.
        4):删除需要被删除的销售订单明细(打破主从关系).
    查询:
        1):查询出销售订单
        2):查询所管理的销售订单明细.
  • SaleBill
package com.revanwang.cascade;

import lombok.Data;

import java.util.ArrayList;
import java.util.List;

@Data
public class SaleBill {
    private Long    id;
    private String  sn;
    private List<SaleBillItem> items = new ArrayList<>();
}
  • SaleBillItem
package com.revanwang.cascade;

import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class SaleBillItem {
    private Long    id;
    private String  product;
    private SaleBill    bill;

    @Override
    public String toString() {
        return "SaleBillItem{" +
                "id=" + id +
                ", product='" + product + '\'' +
                '}';
    }
}
  • salebill.xml
<?xml version="1.0"?>
        <!DOCTYPE hibernate-mapping PUBLIC
                "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
                "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.revanwang.cascade">

    <!--one方-->
    <class name="SaleBill">
        <id name="id">
            <generator class="native"></generator>
        </id>
        <property name="sn"/>
        <bag name="items" inverse="true" cascade="all-delete-orphan">
            <key column="bill_id"></key>
            <one-to-many class="SaleBillItem"/>
        </bag>
    </class>

    <!--many方-->
    <class name="SaleBillItem">
        <id name="id">
            <generator class="native"></generator>
        </id>
        <property name="product"/>
        <many-to-one name="bill" column="bill_id"/>
    </class>

</hibernate-mapping>
  • APPTest
package com.revanwang.cascade;

import com.revanwang.util.HibernateUtil;
import org.hibernate.Session;
import org.junit.Before;
import org.junit.Test;

public class APP {

    @Before
    public void APPTest() {

        SaleBill saleBill = new SaleBill();
        saleBill.setSn("10086");


        SaleBillItem item1 = new SaleBillItem();
        item1.setProduct("显示器");
        item1.setBill(saleBill);

        SaleBillItem item2 = new SaleBillItem();
        item2.setProduct("笔记本");
        item2.setBill(saleBill);

        SaleBillItem item3 = new SaleBillItem();
        item3.setProduct("台式机");
        item3.setBill(saleBill);

        saleBill.getItems().add(item1);
        saleBill.getItems().add(item2);
        saleBill.getItems().add(item3);

        Session session = HibernateUtil.getHibernateSession();
        session.beginTransaction();

        session.persist(saleBill);
        session.persist(item1);
        session.persist(item2);
        session.persist(item3);

        session.getTransaction().commit();
    }

    @Test
    public void getTest() {
        Session session = HibernateUtil.getHibernateSession();
        session.beginTransaction();

        SaleBill saleBill = (SaleBill) session.load(SaleBill.class, 1L);

        session.getTransaction().commit();

        System.out.println(saleBill);
    }

}

组合:只可能由一个模块来同时管理整体和部分的对象.

级联:cascade:代表级联操作,把主对象的操作遍历的在每一个从对象上面执行相同的操作

级联选项:

  • 1、none:缺省值,不做任何级联操作.
  • 2、save-update:在主对象上面执行save/update的方法,级联的保存临时的从对象,更新游离的从对象
  • 3、delete:在主对象上面执行delete方法,级联的删除所有的从对象(要能够级联删除,必须要求在当前主对象里有从对象)
  • 4、all:save-update+delete
  • 5、delete-orphan:删除和主对象打破了关系的明细对象(孤立)
  • 6、all-delete-orphan:all+delete-orphan
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351

推荐阅读更多精彩内容