1-Mybatis基础

1.Mybatis 快速入门

2.Mybatis 相关API

3.Mybatis 映射配置文件

4.Mybatis 核心配置文件

5.Mybatis 传统方式实现Dao层

框架介绍

  • 框架就是半成品软件,我们可以基于这个半成品软件继续开发,完成个性化需求

ORM介绍

  • ORM(Object Relational Mapping): 对象关系映射
  • 指的是持久化数据和实体对象的映射模式,为了解决面向对象与关系型数据库存在的互不匹配的现象的技术
  • 映射规则
    数据表-> 类
    表字段-> 类属性
    表数据-> 对象

原始JDBC的操作弊端

  • 原始JDBC的操作问题分析
    1.频繁创建和销毁数据库的连接会造成系统资源浪费从而影响系统性能
    2.SQL语句在代码中硬编写,如果要修改sql语句,就需要修改java代码,造成代码不易维护
    3.查询操作时,需要手动将结果集中的数据结构封装到实体对象中
    4.增删改查操作需要参数时,需要手动将实体对象的数据设置到sql语句的占位符
  • 原始JDBC的操作问题解决方案
    1.使用数据库连接池初始化连接资源
    2.将sql语句抽取到配置文件中,读取配置文件
    3.使用反射,内省等底层技术,将实体与表进行属性和字段的自动映射

MyBatis介绍

  • MyBatis是一个优秀的基于java的持久层框架,它内部封装了JDBC,时开发这只需要关注SQL语句本省,而不需要花费精力去处理加载驱动,创建连接,创建执行对象等复杂的操作
  • MyBatis通过XML或注解的方式将要执行的各种Statement配置起来,并通过java对象和Statement中SQL的动态参数进行映射生成最终要执行的SQL语句
  • 最后MyBatis框架执行完SQL并将结果映射为Java对象返回.采用ORM思想解决了实体和数据库映射的问题,对JDBC进行了封装,屏蔽了JDBC API底层访问细节,使我们不用和JDBC API打交道,就可以完成对数据库的持久化操作

1.快速入门

1.环境搭建(创建user数据表、编写Student实体类)
2.编写StudentMapper映射文件
mapping文件约束头

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<?xml version="1.0" encoding="UTF-8"?>
    <!--映射配置文件-->
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="StudentMapper">
    <select id="selectAll" resultType="com.itheima.bean.Student">
        SELECT * FROM student
    </select>
</mapper>

3.编写MyBatisConfig核心文件
核心文件约束头

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration 
                  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
                  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--映射配置文件-->
<configuration>
    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://数据库地址/库名"/>
                <property name="username" value="账号"/>
                <property name="password" value="密码"/>
            </dataSource>
        </environment>
    </environments>
<!--加载映射文件-->
    <mappers>
        <mapper resource="StudentMapper.xml"></mapper>
    </mappers>
</configuration>

4.编写测试类

package com.itheima.dao;
import com.itheima.bean.Student;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class StudentTest01 {
    /*
         查询全部
    */
    @Test
    public void selectAll() throws IOException {
        //1.加载核心配置
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
        //2.获取SqlSession工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        //3.通过SqlSession工厂对象获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //4.执行映射配置文件中的sql语句,并接收结果
        List<Student> list = sqlSession.selectList("StudentMapper.selectAll");
        //5.处理结果
        for (Student student : list) {
            System.out.println(student);
        }
        //6.释放资源
        sqlSession.close();
        is.close();
    }
}

2.相关API

Resource

  • org,apache.ibatis.io.Resource: 加载资源的工具类
    核心方法:
    返回值: InputStream
    方法名: getResourceAsStream(String fileName)
    说明: 通过类加载器返回指定资源的字节输入流

SqlSessionFactoryBuilder

  • org.apache.ibatis.session.SqlSessionFactoryBuilder: 获取SqlSessionFactory工厂类对象的功能类
    核心方法:
    返回值: SqlSessionFactory
    方法名: build(InputStream is)
    说明: 通过指定资源字节输入流获取SqlSession工厂类对象

SqlSessionFactory

  • org.apache.ibatis.session.SqlSessionFactpory: 获取SqlSession构架者对象的工厂类接口
    返回值: SqlSession
    方法名: openSession()
    说明: 获取SqlSession构建者对象,并开启手动提交事务
    返回值: SqlSession
    方法名: openSession(boolean autoCommit)
    说明: 获取SqlSession构建者对象,如果参数为true,则开启自动提交事务

SqlSession

  • org.apache.ibatis.session.SqlSession: 构建者对象接口,用于执行SQL,管理事务,接口代理


    方法列表

3.映射配置文件

  • 映射配置文件包含了数据和对象之间的映射关系以及要执行的SQL语句
  • 1.<mapper>: 核心根标签
    namespace属性: 名称空间
  • 2.<select>: 查询功能的标签
  • 4.<insert>: 新增功能标签
  • 5.<update>: 修改功能标签
  • 6.<delete>: 删除功能标签
    标签相同属性
    1.id属性: 唯一标识,配合命名空间使用
    2.resultType属性: 指定结果映射对象类型
    3.parameterType属性: 指定参数隐射对象类型
  • 7.SQL获取参数: #{属性名}

测试单元代码

package com.itheima.dao;

import com.itheima.bean.Student;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class StudentTest01 {
    /*
         查询全部
    */
    @Test
    public void selectAll() throws IOException {
        //1.加载核心配置
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
        //2.获取SqlSession工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        //3.通过SqlSession工厂对象获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //4.执行映射配置文件中的sql语句,并接收结果
        List<Student> list = sqlSession.selectList("StudentMapper.selectAll");
        //5.处理结果
        for (Student student : list) {
            System.out.println(student);
        }
        //6.释放资源
        sqlSession.close();
        is.close();
    }
    /*
         根据id进行查询
    */
    @Test
        public  void selectById() throws IOException {
            //加载核心配置文件
            InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
            //获取SqlSession工厂对象
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            //通过工厂对象获取SqlSession对象
            SqlSession sqlSession = sqlSessionFactory.openSession();
            //执行映射配置文件中的sql语句,并接收结果
            Student stu = sqlSession.selectOne("StudentMapper.selectById", 1);
            //打印结果
            System.out.println(stu);
            //释放资源
            sqlSession.close();
            is.close();
        }
    /*
         新增学生方法
    */
    @Test
    public  void insert() throws IOException {
        //加载核心配置文件
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
        //获取工厂类对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        //通过工厂类对象获取SqlSession对象
        //SqlSession sqlSession = sqlSessionFactory.openSession();
        //通过给定布尔类型的参数为true,开启自动提交事务
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //执行映射配置文件中的sql语句,并接收结果
        Student stu = new Student(5, "周期", 77);
        int insert = sqlSession.insert("StudentMapper.insert",stu);
        //对于增删改,提交事务
        //sqlSession.commit();
        System.out.println(insert);
        //释放资源
        sqlSession.close();
        is.close();
    }
    /*
         修改学生方法
    */
    @Test
    public  void update() throws IOException {
        //加载核心配置文件
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
        //获取工厂类对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        //通过工厂类对象获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //执行映射配置文件中的sql语句,并接收结果
        Student stu = new Student(5, "周七", 27);
        int result = sqlSession.update("StudentMapper.update",stu);
        //对于增删改,提交事务
        sqlSession.commit();
        System.out.println(result);
        //释放资源
        sqlSession.close();
        is.close();
    }
    /*
         删除学生方法
    */
    @Test
    public  void delete() throws IOException {
        //加载核心配置文件
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
        //获取工厂类对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        //通过工厂类对象获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //执行映射配置文件中的sql语句,并接收结果
        int result = sqlSession.delete("StudentMapper.delete",5);
        //对于增删改,提交事务
        sqlSession.commit();
        System.out.println(result);
        //释放资源
        sqlSession.close();
        is.close();
    }
}

映射配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!--映射配置文件-->
<!-- 约束文件头-->
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="StudentMapper">
<!--    查询功能-->
    <select id="selectAll" resultType="com.itheima.bean.Student">
        SELECT * FROM student
    </select>
<!--    根据id查询-->
    <select id="selectById" resultType="com.itheima.bean.Student" parameterType="java.lang.Integer">
        select * FROM student where id = #{id}
    </select>
<!--    新增功能-->
    <insert id="insert" parameterType="com.itheima.bean.Student">
        insert into student values (#{id},#{name},#{age})
    </insert>
<!--    修改功能-->
    <update id="update" parameterType="com.itheima.bean.Student">
        update student set name=#{name},age=#{age} where id=#{id}
    </update>
<!--    删除功能-->
    <delete id="delete" parameterType="java.lang.Integer">
        delete from student where id=#{id}
    </delete>
</mapper>

4.核心配置文件

  • 核心配置文件包含了MyBatis最核心的设置和属性信息,如数据库的连接,事务,连接池信息等

对配置文件进行说明

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--映射配置文件-->
<configuration>
<!--    environments配置数据库环境标签,环境可以有多个,default属性指定使用的是哪个-->
<!--    利用environment标签可以配置多个数据库信息标签如mysql1,mysql2等等,最终使用哪个,要environments 标签中的 default属性来选择-->
    <environments default="mysql">
<!--    environment配置数据库信息标签 id属性代表唯一的标识-->
        <environment id="mysql">
<!--            transactionManager事务的管理标签 type属性,采用JDBC默认的事务-->
            <transactionManager type="JDBC"></transactionManager>
<!--            dataSource数据源标签 type属性 连接池-->
            <dataSource type="POOLED">
<!--                property获取数据库连接的数据信息标签-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://IP地址:3306/库名"/>
                <property name="username" value="用户"/>
                <property name="password" value="密码"/>
            </dataSource>
        </environment>
    </environments>

<!--        mappers引入映射配置文件标签-->
    <mappers>
<!--        mapper 引入指定的映射配置文件 resource属性: 指定映射配置文件的名称-->
        <mapper resource="StudentMapper.xml"></mapper>
    </mappers>
</configuration>

数据库配置文件引入

  • <properties>: 引入数据库连接信息配置文件标签
  • 属性
    resource: 数据库连接配置文件路径
  • 获取数据库连接参数: ${键名}

编写一个JDBC数据库配置文件

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://IP地址:3306/数据库名
username=用户
password=密码

在核心配置文件中引入JDBC数据库配置文件,其他配置不变

<!--引入数据库连接的配置文件-->
<properties resource="JDBC.properties"/>

<!--property获取数据库连接的数据信息-->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>

核心配置文件-起别名的使用

  • <typeAliases>: 为全类名起别名的父标签
  • <typeAlias>: 为全类名起别名的子标签
  • 属性
    type: 指定全类名
    alias: 指定别名
  • <package>: 为指定包下所有类型起别名的子标签(别名就是类名)

在核心配置文件<configuration>标签中添加起别名标签,其他配置不变

<!--    起别名-->
    <typeAliases>
        <typeAlias type="com.itheima.bean.Student" alias="student"/>
    </typeAliases>

映射配置文件修改 对com.itheima.bean.Student全类名的引用,其他配置文件不变

<?xml version="1.0" encoding="UTF-8"?>
<!--映射配置文件-->
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="StudentMapper">
<!--    查询功能-->
    <select id="selectAll" resultType="student">
        SELECT * FROM student
    </select>
<!--    根据id查询-->
    <select id="selectById" resultType="student" parameterType="java.lang.Integer">
        select * FROM student where id = #{id}
    </select>
<!--    新增功能-->
    <insert id="insert" parameterType="student">
        insert into student values (#{id},#{name},#{age})
    </insert>
<!--    修改功能-->
    <update id="update" parameterType="student">
        update student set name=#{name},age=#{age} where id=#{id}
    </update>
<!--    删除功能-->
    <delete id="delete" parameterType="student">
        delete from student where id=#{id}
    </delete>
</mapper>

常见的自带的别名


常见自带别名的包

5.Mybatis 传统方式实现Dao层

Dao 层传统实现方式

  • 分层思想: 控制层(controller),业务层(service),持久层(dao)
  • 调用流程
    控制层->业务层->持久层->DB
    结构目录

    1.三个配置文件内容不变
    2.编写的Student类和之前一样,成员变量和Mysql的表字段对齐
    3.持久层mapper目录下的StudentMapperImpl实现类和StudentMapper接口代码
package com.itheima.mapper;
import com.itheima.bean.Student;
import java.util.List;
/*
    持久层接口
 */
public interface StudentMapper {
    //查询全部
    public abstract List<Student> selectAll();
    //条件查询
    public abstract Student selectById(Integer id);
    //新增数据
    public abstract Integer insert(Student stu);
    //更新全部
    public abstract Integer update(Student stu);
    //删除全部
    public abstract Integer delete(Integer id);
}
package com.itheima.mapper.impl;

import com.itheima.bean.Student;
import com.itheima.mapper.StudentMapper;
import com.sun.corba.se.impl.resolver.SplitLocalResolverImpl;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/*
    持久层实现类
 */
public class StudentMapperImpl implements StudentMapper {
    //查询全部
    @Override
    public List<Student> selectAll() {
        InputStream is = null;
        SqlSession sqlSession = null;
        List<Student> list = null;
        try {
            //加载核心配置文件
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            //获取SqlSession工厂对象
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            //通过工厂对象获取SqlSession对象
            sqlSession = sqlSessionFactory.openSession(true);
            //执行映射配置文件中的sql语句,并接收结果
            list = sqlSession.selectList("StudentMapper.selectAll");

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            if (sqlSession != null) {
                sqlSession.close();
            }

            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //返回结果
        return list;
    }

    //根据id查询
    @Override
    public Student selectById(Integer id) {
        InputStream is = null;
        SqlSession sqlSession = null;
        Student stu = null;
        try {
            //加载核心配置文件
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            //获取SqlSession工厂对象
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            //通过工厂对象获取SqlSession对象
            sqlSession = sqlSessionFactory.openSession(true);
            //执行映射配置文件中的sql语句,并接收结果
            stu = sqlSession.selectOne("StudentMapper.selectById", id);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            if (sqlSession != null) {
                sqlSession.close();
            }

            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //返回结果
        return stu;
    }

    //新增数据
    @Override
    public Integer insert(Student stu) {
        InputStream is = null;
        SqlSession sqlSession = null;
        Integer result = null;
        try {
            //加载核心配置文件
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            //获取SqlSession工厂对象
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            //通过工厂对象获取SqlSession对象
            sqlSession = sqlSessionFactory.openSession(true);
            //执行映射配置文件中的sql语句,并接收结果
            result = sqlSession.insert("StudentMapper.insert", stu);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            if (sqlSession != null) {
                sqlSession.close();
            }

            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //返回结果
        return result;
    }

    //修改数据
    @Override
    public Integer update(Student stu) {
        InputStream is = null;
        SqlSession sqlSession = null;
        Integer result = null;
        try {
            //加载核心配置文件
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            //获取SqlSession工厂对象
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            //通过工厂对象获取SqlSession对象
            sqlSession = sqlSessionFactory.openSession(true);
            //执行映射配置文件中的sql语句,并接收结果
            result = sqlSession.update("StudentMapper.update", stu);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            if (sqlSession != null) {
                sqlSession.close();
            }

            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //返回结果
        return result;
    }

    //删除数据
    @Override
    public Integer delete(Integer id) {
        InputStream is = null;
        SqlSession sqlSession = null;
        Integer result = null;
        try {
            //加载核心配置文件
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            //获取SqlSession工厂对象
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            //通过工厂对象获取SqlSession对象
            sqlSession = sqlSessionFactory.openSession(true);
            //执行映射配置文件中的sql语句,并接收结果
            result = sqlSession.delete("StudentMapper.delete", id);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            if (sqlSession != null) {
                sqlSession.close();
            }

            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //返回结果
        return result;
    }
}

4.业务层Service目录下的StudentServiceImpl实现类和StudentService接口代码

package com.itheima.service;

import com.itheima.bean.Student;
import java.util.List;

/*
    业务层接口
 */
public interface StudentService {
    //查询全部
    public abstract List<Student> selectAll();
    //根据id查询
    public abstract Student selectById(Integer id);
    //新增数据
    public abstract Integer insert(Student stu);
    //修改数据
    public abstract Integer update(Student stu);
    //删除数据
    public abstract Integer delete(Integer id);
}
package com.itheima.service.Impl;

import com.itheima.bean.Student;
import com.itheima.mapper.StudentMapper;
import com.itheima.mapper.impl.StudentMapperImpl;
import com.itheima.service.StudentService;
import java.util.List;
/*
    业务层实现类
 */
public class StudentServiceImpl implements StudentService {
    //创建持久层对象
    private StudentMapper mapper = new StudentMapperImpl();

    @Override
    public List<Student> selectAll() {
        return mapper.selectAll();
    }

    @Override
    public Student selectById(Integer id) {
        return mapper.selectById(id);
    }

    @Override
    public Integer insert(Student stu) {
        return mapper.insert(stu);
    }

    @Override
    public Integer update(Student stu) {
        return mapper.update(stu);
    }

    @Override
    public Integer delete(Integer id) {
        return mapper.delete(id);
    }
}

LOG4J

  • 在日常开发过程中,排查问题是难免需要输出MyBatis真正执行的SQL语句,参数,结果等信息,我们就可以借助LOG4J的功能来实现执行信息的输出
  • 使用步骤
    1.导入jar包
    2.修改核心配置文件,添加<settings>标签
<!--    继承LOG4J日志信息-->
    <settings>
        <setting name="logImpl" value="log4j"/>
    </settings>
核心配置文件报错

原因: 注意标签的先后顺序<settings>标签要在<properties>后面,

3.在src下编写LOG4J配置文件,配置文件为log4j.properties要不然会报错

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

推荐阅读更多精彩内容