Hibernate学习笔记

本节重点:
1、hibernate映射文件
2、hibernate核心配置文件
3、hibernate核心类


1、hibernate(orm)入门(实体类+映射文件+核心配置文件)
1)orm的理解
orm(object relation mapping )
对象的名字 表名
对象的属性名称 列名
对象属性类型 列的类型

2)hibernate工程搭建步骤:(一个实体+一个映射文件+一个核心配置文件)
    准备工作:数据库表
    第一步:导入/lib/required/目录下的jar+mysql连接驱动+日志相关jar
    第二步:创建实体Customer(类不能加上final+有主键+提供get/set方法+无参构造)
    第三步:创建实体映射文件Customer.hbm.xml(hibernate-mapping/class/id+property)
    第四步:创建核心配置文件hibernate.cfg.xml(hibernate-configuration/session-factory/property)
    注意:xml文件头信息需要手动复制一下,解决xml红色圈圈以及提示需要手动在本地引入约束文件

3)测试操作数据
    Configuration-->SessionFactory-->Session(get/load,save,update,delete)
    save(customer);
    update(customer);
    delete(customer);
    get(xx.class,1l); 
    load(xx.class,1l);

2、详细讲解:映射文件+核心配置文件
映射文件Customer.hbm.xml:
<hibernate-mapping>
<class>
<id name="" column="">
<generator class="native/sequence/identity"/>
</id>
<property name="" column=""></property>
</class>
<hibernate-mapping>

核心配置文件hibernate.cfg.xml:
    <hibernate-configuration>
        <session-factory>
            <property name="" column=""></property>
            <mapping resource=""/>
        </session-factory>
    <hibernate-configuration>
    
注意:hibernate核心配置文件中hibernate.hbm2ddl.auto=create/update
create: 每次都会创建新的表,一般测试中使用
update: 数据库中没有表,就创建表;
  表结构和我们定义的实体映射文件表结构是否一致,不一致就做alter table操作

3、hibernate核心类(Configuration+SessionFactory+Session+Trasaction,首先理解,然后再去操作怎么得到该对象)
1)Configuration(加载配置文件的配置)
//默认去加载src下面的hibernate.cfg.xml文件,在加载核心配置文件的时候要保证加载实体映射文件
Configuration configure=new Configuration().configure();

2)SessionFactory(生产Session的工厂)
    sessionFactory=configuration.buildSessionFactory();

====================================================================================================================================
1、开发规律:4个方面
请求路径
form表单 action写路径 表单提交
超链接 <a href="xxx"> 点击超链接
点击按钮 调用一个js函数 js函数里面可以 $.get() $.post() $.ajax()
请求方式
post/get put/delete
请求参数
从页面传递,java类获取
form表单 name="xxx" post
url带参数 xxxx?username=aaaa&password=123456 get
js里面 $.get() $.post() $.ajax()都可以带参数

        传统方式:request.getParameter("参数名");
        Struts2框架属性驱动/模型驱动
        
    响应数据
        传统方式:response.getWriter().write("json字符串");
        Struts2:把数据放到值栈, result type="json"

2、存值取值:
    java类把数据放到某个地方,页面获取
        传统方式:域对象 request 页面通过${}
        Struts2:把数据放到值栈 页面通过Struts2标签+Ognl表达式
            push(对象);       <s:property value="[0].top" />
            set("键",对象);   <s:property value="键的名字" />
            list集合          <s:iterator  />
            map集合           <s:iterator  />
3、注解
    一个一个对应xml配置
4、hibernate
    xml文件有红色xx  jar包导入/dtd约束文件/xml配置节点是否正确
    
    准备工作:准备数据库 表
    建工程,导jar包
    映射文件   实体类与表
    核心配置文件 关联映射文件
    
    Configuration 加载配置核心配置  hibernate.cfg.xml
        核心配置加载映射文件,框架才知道哪个类与哪个数据的哪张表对应
    创建SessionFactory
    获取Session 
    开启事务
    增删改查
    提交事务
    关闭Session

本节重点:
1、hibernate核心类
2、持久态对象的状态
3、持久态对象方法


3)Session(操作数据库的Session会话)
    Session是一个非线程安全的对象  与线程绑定
    造成线程不安全问题=多线程+全局变量  
    怎么解决Session的线程不安全问题?
    解决方法一:在方法内部创建Session
    解决方法二:getCurrentSession()
    其他办法:使用ThreadLocal,变量副本
    
    Session session=sessionFactory.openSession();// 操作完数据库之后需要手动关闭session
    Session session=sessionFactory.getCurrentSession(); // 从当前线程中获取session,session操作完数据库之后,不需要手动关闭session

    save   保存对象
    update 修改对象
    delete 删除对象
    get/load 根据id进行查询
    saveOrUpdate 执行save或update操作
    createQuery() 获取一个Query对象
    createSQLQUery()获取一个可以操作sql的SQLQuery对象
    createCriteria() 获取一个Criteria它可以完成条件查询

4)Transaction(操作数据库的事务)
    (1)如果不手动开启事务,默认一个session操作就是一个事务,
        hibernate默认是hibernate.connection.autocommit=false也即并非自动提交事务
        怎么证明?在hibernate.cfg.xml中配置<property name="hibernate.connection.autocommit">true</property>
        然后发现即便代码中有异常,异常之前的一个事务还是正常提交了
    (2)如果手动开启事务,那就从开启事务到事务提交中间的整个操作都是一个事务
    (3)基本操作
        // 开启事务,获取的事务对象
        Transaction  transaction=session.beginTransaction();
        //事务提交
        transaction.commit();
        //事务回滚
        transaction.rollback();

5)Query(hql查询接口) 
    HQL:hibernate的query语言(面向对象的角度去理解这个类似于sql的查询化语言)
    HQL语句中根本看不到跟表相关任何信息
    Query query =session.createQuery(hql);
    hql: select name,address from Customer;
    2种方式可以封装数据:
    第1种:通过List<Object[]>,这里Object[]封装了name和address值
    第2种:通过投影的方式 new Customer(name,address)
    // int pageNo = 1   int pageSize=10
    setFirstResult((pageNo-1)*pageSize) 
    setMaxResults(pageSize)
    与msyql的limit分页传参一致
    setParameter()给?设置值,从0开始
    
6)SQLQuery(原生sql查询接口)
    SQLQuery sqlQuery=session.createSQLQuery("select * from t_customer");
    使用List<Object[]> 或者 sqlQuery.addEntity(Customer.class);去封装查询数据
    
7)Criteria(条件接口QBC)
    Criteria criteria=session.createCriteria(Customer.class);
    Restrictions 条件有关都封装进去了,语法参照sql写法

1、hibernate中的持久化实体类书写要求(使用hibernate框架注意书写实体的规范)
1)实体类不要使用final(因为hibernate会根据实体产生代理对象)
2)实体类中有唯一的OID来与表中主键对应(hibernate中缓存要使用)
3)尽量使用包装类型而不是普通类型(一些基本类型属性插入表中都会将默认值存入,而包装类型默认值是null)
4)实体类成员变量提供get和set方法(标准的jpa要求属性提供get和set)
5)提供public无参构造(hibernate和jpa需要)
注意:get和load的区别
(1)get:采用的是立即加载,执行到该行代码的时候,马上发送SQL语句进行查询。
load:采用的是延迟加载(lazy),执行到该行代码的时候,不会马上发送SQL语句,
只有真正使用这个对象的时候(使用这个对象的普通属性的时候)才会发送SQL语句。
(2)get:查询之后返回的是真实对象本身,对象没有查找到返回null。
load:查询之后返回的是一个代理对象,是我们持久化实体类的子类,
查询不到的对象会出现一个exception。

2、主键类型和主键生成策略
1)主键类型
自然主键和代理主键
居民表1:identityCardId(身份证id),name(姓名)
居民表2:id(主键),identityCardId(身份证id),name(姓名)
居民表1中:身份证id是自然主键
居名表2中:id是代理主键
注意:开发中采用代理主键!

2)主键生成的常用类型(主键生成策略)
    主键赋值,是谁去负责给主键赋值?
    hibernate                数据库自己去赋值                自己手动去给主键赋值
    increment/uuid              identity/sequence/native         assigned
    负责代理主键:identity(就是mysql auto_increment)/sequence(oracle中序列)/native/increment/uuid
    负责自然主键:assgined
    create sequence seq_mysequence;
    seq_mysequence.currVal
    seq_mysequence.nextVal
    注意:在实际过程使用最多的是identity/sequence/native/uuid(给所在表主键赋值,该主键的类型必须是字符串)

3、持久化对象的三种状态(必须理解)
1)三种状态(从2个维度去衡量一个持久对象的状态:session管理+对象OID是否有值)
瞬时态(没有oid值,没有交给session管理)
持久态(有oid值,交给了session管理) 重点理解
游离态/脱管态(有oid值,没有交给session管理)
oid的值:创建实体中跟表主键映射的成员变量是否有值
session管理:就是session去操作的所在范围

2)三种状态之间的切换
    瞬时态转换成持久态:save(),saveOrUpdate()
    游离态/脱管态转换成持久态:update(),saveOrUpdate()
    其他情况转换成持久态:get()/load()/find()/qbc 查询

4、hibernate中的一级缓存(本地要去测试) Tair pair
1)持久化对象为什么具有自动更新数据库的能力?
session对象有一级缓存和快照,通过watch查看session
一级缓存(缓存实体对象):
session -> persistenceContext -> entityEntryContext -> head -> entityInstance
快照(将缓存数据copy一个副本):
session -> persistenceContext -> entityEntryContext -> head -> entiryEntry -> loadedState

    原理:底层就是将缓存数据进行修改,提交事务时对比一级缓存和快照区是否相同,
    如果不同就会发update操作,以一级缓存的数据为准
    
2)一级缓存常用的操作
    (1)只有持久化态对象才会放入到session一级缓存中
    (2)clear/evict/refresh介绍
        clear(): 清除session 一级缓存
        evict(c):清除session 一级缓存中指定的对象
        refresh(c):从数据库同步到缓存中去
        close():session已经关闭,当然会清空session一级缓存

3)持久化对象去操作数据库
    get()/load()/Query的list查询/
    save()/update()/saveOrUpdate()
    saveOrUpdate(){
        if(oid!=null){
            update();
        }else if(oid==null){
            save();
        }
    }
    以上操作都会将数据放到一级缓存中,此时我们可以理解成这些对象交给了session管理
    注意:(1)在实际开发过程中,对于update,delete操作,我们一般采取的步骤是先查询
         再去做操作,而不是创建一个对象通过赋值id来操作
         (2)通过实验证明OID要唯一,OID要与数据库记录对应

====================================================================================================================================
本节重点:
1、一对多
2、inverse 与 cascade
3、注解一对多 多对多


5、hibernate一对多关联配置及其操作(理解)
专业术语理解
级联:cascade <set cascade="save-update">
维护:inverse <set inverse="true">
1)一对多关联实体及其映射文件配置(必须掌握)
Order private Customer c;
Customer private Set<Order> orders;

    Order.hbm.xml
    <many-to-one  class="对方实体类完整类路径" column="外键名字">
    
    Customer.hbm.xml
    <set name="orders">
        <key column="外键名字" />
        <one-to-many class="对方实体类完整类路径" />
    </set>

2)双向关联操作(理解)
    // 订单关联客户
    o1.setC(c);
    o2.setC(c);
    
    // 客户关联订单
    c.getOrders().add(o1);
    c.getOrders().add(o2);

    session.save(o1);
    session.save(o2);
    session.save(c);
    
    (1)如果不配置inverse或者是配置inverse="false",此时两方都在维护外键,就是给外键设置值
    (2)如果我们在一的一方配置inverse="true",外键由对方来维护
    (3)外键在哪边,就由哪边维护,多的一方维护

3)单向关联操作
    情况一:
    // 订单关联客户
    o1.setC(c);
    o2.setC(c);
    // 保存订单
    session.save(o1); 
    session.save(o2); 
    
    报错: org.hibernate.TransientObjectException: object references an unsaved transient instance 
    - save the transient instance before flushing: cn.itheima.oneToMany.Customer
    持久态对象引用了瞬时态对象
    怎么理解?瞬时态对象在数据表里没有对应记录生成,当然也没有OID
    最后提交事务,订单表中的外键值没有
    
    怎么解决?
    (1)手动保存
    (2)级联保存 cascade 保存A的时候也保存B,级联配置在A

    情况二:
    // 客户关联订单
    c.getOrders().add(o1);
    c.getOrders().add(o2);
    // 保存客户
    session.save(c);

4)对象导航(cascade理解)
    实验前提:两方都设置了cascade="save-update"
    有几条insert语句,要看有多少关联
    o1.setC(c);
    // c要关联o2 o3
    c.getOrders().add(o2);
    c.getOrders().add(o3);
    session.save(o1);
    
5)级联操作(理解)
    在Order.hbm.xml  <many-to-one cascade="save-update" > 保存Order会保存Customer
    在Customer.hbm.xml <set cascade="save-update" >保存Customer会保存Order
    结论:在A配置cascade="save-update",就是保存A的时候也保存B
          在A配置cascade="delete",就是删除A的时候也删除B中跟A有关联的记录
          在A配置cascade="delete-orphan",删除与当前对象解除关系的对象

hibernate第3天总结(注解)
1、注解实现一对多(重点)
1)常用注解
(1)表相关映射注解:@Entity @Table
(2)主键相关映射注解:@Id @GeneratedValue 主键生成策略
@GenericGenerator(name = "myuuid", strategy = "uuid")
@GeneratedValue(generator = "myuuid")
(3)列相关映射注解:
改变表中列名+改变列长度+表中列约束:@Column
改变列的类型:@Type @Temporal
(4)@Transient:该列不会生成在数据表中
2)注解实现一对多
(1)在hibernate.cfg.xml文件中去加载映射文件<mapping class="cn.itheima.domain.Book" />
(2)Customer在一的一方:@OneToMany mappedBy="c" 这里的c要与Order里面的private Customer c对应
(3)Order在多的一方:@ManyToOne @JoinColumn声明外键

2、注解实现多对多(重点)
Student @ManyToMany
Teacher @ManyToMany
声明中间表:@JoinTable(@JoinColumn,@JoinColumn)
====================================================================================================================================
回顾:
1、什么叫维护外键?
就是保证外键有值
一个字段在B表中是外键,一定在A表中是主键,B表的这个外键
是根据A表的主键来生成的,A表的主键一定要有值,否则B表这个外键生成不了

    概念:(父)主表A和(子)从表B,外键在哪个表,哪个表就是从表
    
2、为什么要维护外键?
    保证数据的完整性
    
3、谁来维护外键?怎么维护外键?
    默认是两方都来维护,并且多的一方一直都会有维护的权利
    
    多的一方维护,参考hibernate-demo3/test2
    o1.setC(c);
    o2.setC(c);
    session.save(o1); 
    session.save(o2);
    维护的时候为什么要有级联?
    因为一个字段在B表中是外键,一定在A表中是主键,B表的这个外键
    是根据A表的主键来生成的,主键都没有值,外键怎么产生呢?所以要加级联
    
    一的一方维护,参考hibernate-demo3/test3
    c.getOrders().add(o1);
    c.getOrders().add(o2);
    session.save(c);
    维护的时候为什么要有级联?
    因为一的一方在维护,t_order表的记录都没有生成,怎么维护?所以要加级联
    
4、inverse在所有实验中可以最后考虑,一般在一的一方加上inverse="true"

get/load
private class A{
    private Set<B> b;
    private String name;
    private C c;
}

本节重点:
1、注解配置一对一
2、查询的3种方式(HQL、QBC、原生sql)
3、HQL连接查询(内连接/外链接、迫切内连接/迫切左外链接)

3、注解实现一对一(重点)
User:@OneToOne(targetEntity = IDCard.class, mappedBy = "user")
IdCard:@OneToOne @JoinColumn(name = "c_user_id")
1)借助外键来实现一对一(非常常用)
2)借助主键来实现一对一(了解)

所有注解有个规律:mappedBy和JoinColumn是互斥的

4、检索方式总结(查询数据的5种方式)(重点)
1)对象导航查询
Customer customer=session.get(Customer.class,2);
customer.getOrders().size();

2)根据主键查询
    session.get(Customer.class,2)/load(Customer.class,2)

3)HQL查询(通过Query查询) 
    select  new Customer(name,money)  from where group by order by 
    Query query=session.createQuery(HQL);
    基本查询:
    排序:from Order order by money desc
    条件:from Order where money >?/:mymoney
    分页:setFirstResult()/setMaxResults()
    统计分组:select sum(money) from Order group by c
    投影:select new Customer(name,address) from Customer; List<Object[]>
    命名(了解):@NamedQuery   Query query=session.createNamedQuery("")
    常用的方法:list(),setParameter(序号从0开始),setFirstResult()/setMaxResults(),uniqueResult()

4)QBC查询(通过Criteria查询) Order(排序)、Restrictions
    Criteria criteria=session.createCriteria(实体对象.class);
    Restrictions.gt()/eq()/like()/
    criteria.and()
    criteria.add()
    criteria.setProjection(Projections)
    基本查询:
    排序:Order
    条件:Restrictions
    分页:setFirstResutlt() setMaxResults()
    统计分组:Projections
    离线查询:(了解)
    Criteria常用的方法:list(),add(),addOrder(),setProjection()

5)SQL查询(通过SQLQuery查询,原生sql)
    SQLQuery sqlQuery=session.createSQLQuery(sql);
    SQLQuery对象常用的方法:addEntity(xx.class)

回顾内连接和外连接:
内连接:
交叉连接:select * from emp e cross join dept d;
显式内连接:select * from emp e inner join dept d on e.deptno=d.deptno;
隐式内连接:select * from emp e , dept d where e.deptno=d.deptno;
外连接:
A a left join B b on a.col1=b.col2 outer可以省略
A a right join B b on a.col1=b.col2
orcle:
A a , B b where a.col1(+)=b.col2
A a , B b where a.col1 =b.col2(+)
select d.deptno 部门编号,d.dname 部门名称,count(e.empno) 部门总人数 from emp e, dept d where e.deptno(+)=d.deptno
group by d.deptno,d.dname order by d.deptno;

1、HQL 连接(通过"."来关联另外一个表,使用fetch 查询数据封装到from 后面对象中)(掌握)
1)显示内连接
from Customer c inner join c.orders with xx /where xx
使用with 底层使用 t_customer c inner join t_order o on c.id=o.id and (xx)
使用where底层使用 t_customer c inner join t_order o on c.id=o.id where xx;
查询的结果是对象:Customer Order
注意下面这种写法语法报错:
String hql = "from Customer c inner join Order o with c.id=1"

2)隐式内连接(了解)
   from Customer c where c.orders.id=xxx;
   隐式内连接不能写成 from Customer c ,c.orders (错误写法)
   注意下面这种写法语法报错:
   String hql = "from Order o,o.c where o.c.id=1"
     
3)迫切内连接
   from Customer c inner join fetch c.orders
   fetch将查询的数据封装到Customer中,迫切想得到Customer
   
   内连接与迫切内连接的区别:
       (1)inner join/ inner join fetch
       (2)内连接查询得到的结果是List<Object[]>
          迫切内连接查询得到的结果是List<Order>/List<Customer>,集合里是from后面的对象
       (3)实际应用的时候根据需要选择使用
   
4)外连接
   from Customer c left outer join c.orders  outer可以省略
   查询的结果是:List<Object[]>
   
5)迫切左外连接
   from Customer c left outer join fetch c.orders     outer可以省略
   fetch将查询的数据封装到Customer中,迫切想得到Customer
   注意:fetch不能和with联合使用

2、hibernate事务和session配置(了解)
1)hibernate事务管理
hibernate支持的事务的隔离级别
1 Read UnCommitted
2 Read Committed 是oracle默认的隔离级别
4 Repeatable Read 是mysql默认的隔离级别
8 Serializable
<property name="hibernate.connection.isolation">4</property> //代表当前隔离级别是Repeatable Read
2)hibernate的session管理(在分布式环境下,session很容易造成不安全问题)
在hibernate.cfg.xml中配置
<property name="hibernate.current_session_context_class">thread</property>
掌握下面这种写法:
Session session=sessionFactory.getCurrentSession();//从线程中拿到session是安全的

3、查询分类(理解)
1)类级别查询
Customer customer=session.get(Customer.class,1L);
Customer customer$=session.load(Customer.class,1L);
所谓类级别查询,就是执行查询某一个类的数据
load是延迟加载查询的,其底层是采用代理对象来完成延迟加载,所以Customer不要加final
默认的类级别的延迟属性lazy=true,可以在类上配置注解@Proxy(lazy="true")
或者映射文件上配置<class lazy="true">
延迟加载对象初始化:Hibernate.initialize(c1);

2)关联级别查询
    c.getOrders().size()

====================================================================================================================================
本节重点:
1、fetch+lazy
2、hibernate总结及规律

4、优化:查询策略(抓取策略) 理解:fetch+lazy
1)配置fetch和lazy
(1)fetch和lazy
fetch能够指定sql语句的格式:
select 多条简单的sql,默认值
join 采用迫切左外连接
subselect 将生成子查询的sql
lazy能够控制sql语句何时发出,是性能问题
(2)在映射文件中取值,有相应注解对应
<set fetch="select,join,subselect" lazy="true,false,extra"></set>
<many-to-one fetch="join,select" lazy="false,proxy,no-proxy"/>
<one-to-one fetch="join,select" lazy="false,proxy,no-proxy" />
(3)企业中常用
应用场景:
商品列表 延迟加载
商品详情页 立即加载
得到商品关联的促销活动的总数 加强的延迟加载

        多加载一的时候,立即加载:
        @Fetch(FetchMode.JOIN)
        @LazyToOne(LazyToOneOption.FALSE)
        private  Customer c;
        一加载多的时候,延迟加载:
        @Fetch(FetchMode.SELECT)
        @LazyCollection(LazyCollectionOption.TRUE)
        private Set<Order> orders = new HashSet<Order>();
    
2)批量查询
    配置BatchSize目的是解决根据一方查询另外一方的时候,减少sql语句查询将需要被查询对象的id放入到in语句
    配置BatchSize原则:
    在主表上配置
    查询Customer的时候把Order查询出来
    @BatchSize(size=3)
    private Set<Order> orders = new HashSet<Order>();
    查询Order的时候把Customer查询出来
    @BatchSize(size=3)
    public class Customer 

hibernate核心总结:
1、hibernate项目独立完成
1)实现的步骤
第一步:导入/lib/required/目录下的jar+mysql连接驱动+日志相关jar+lib\optional\c3p0下包
第二步:创建实体Customer(类不能加上final+有主键+提供get/set方法+无参构造)
第三步:创建实体映射文件Customer.hbm.xml(hibernate-mapping/class/id+property)
第四步:创建核心配置文件hibernate.cfg.xml(hibernate-configuration/session-factory/property)

2)hibernate的核心api
    Configuration config=new Configuration().configure();
    SessionFactory sessionFactory=config.buildSessionFactory();
    Session session=sessionFactory.openSession();/getCurrentSession();
    session.beginTransaction();
    session.get()/load()/save()/update()/delete()
    session.getTransaction().commit();
    session.close();

2、查询
1)HQL(select from where group by order by)
Query query=session.createQuery("from Customer");
query.list()/setFirstResult()/setMaxResults()/uniqueResult()/setParameter()/
List<Object[]>
投影:select new Customer(name,address) from Customer;
2)QBC(Criteria)
Criteria criteria=session.createCriteria(Customer.class);
criteria.add(criteria...)
Restrictions
Projections
3)sql(SQLQuery)
SQLQuery sqlQsuery=session.createSQLQuery(sql);
addEntity(Customer.class);

3、一对多的维护外键和级联
cascade:级联
inverse:反转

4、一对多、一对一、多对多注解配置
把握规律:
1)有外键的一方配置JoinColumn,另一方配置mappedBy=""
2)保存的时候,保存有外键的这一方,级联保存另一方

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

推荐阅读更多精彩内容