Mybatis框架

Mybatis

创建数据库

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) NOT NULL COMMENT '用户名称',
  `birthday` date DEFAULT NULL COMMENT '生日',
  `sex` char(1) DEFAULT NULL COMMENT '性别',
  `address` varchar(256) DEFAULT NULL COMMENT '地址',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', '王五', null, '2', null);
INSERT INTO `user` VALUES ('10', '张三', '2014-07-10', '1', '北京市');
INSERT INTO `user` VALUES ('16', '张小明', null, '1', '河南郑州');
INSERT INTO `user` VALUES ('22', '陈小明', null, '1', '河南郑州');
INSERT INTO `user` VALUES ('24', '张三丰', null, '1', '河南郑州');
INSERT INTO `user` VALUES ('25', '陈小明', null, '1', '河南郑州');

Mybatis框架原理(掌握)

1、Mybatis 是什么?

Mybatis 是一个持久层的架构,是 apache 下的顶级项目。

Mybatis 原先是托管在 googlecode 下,再后来是托管在 Github 上。

Mybatis 让程序员将主要的精力放在 sql 上,通过 Mybatis 提供的映射方式,自由灵活生成(半自动,大部分需要程序员编写 sql )满足需要 sql 语句。

Mybatis 可以将向 preparedStatement 中的输入参数自动进行输入映射,将查询结果集灵活的映射成 java 对象。(输出映射

2、Mybatis 框架

image.png
image

注解:

  • SqlMapConfig.xml (Mybatis的全局配置文件,名称不定)配置了数据源、事务等 Mybatis 运行环境

  • Mapper.xml 映射文件(配置 sql 语句)

  • SqlSessionFactory (会话工厂)根据配置文件配置工厂、创建 SqlSession

  • SqlSession (会话)面向用户的接口、操作数据库(发出 sql 增删改查)

  • Executor (执行器)是一个接口(基本执行器、缓存执行器)、SqlSession 内部通过执行器操作数据库

  • Mapped Statement (底层封装对象)对操作数据库存储封装,包括 sql 语句、输入参数、输出结果类型

上图是集成到Spring框架的MyBaits技术架构图。架构图分为两部分:虚线框外的是Spring框架的业务逻辑处理类,它调用Mybatis的DAO接口发起对数据库的增删改查请求;虚线框内的是Mybatis框架部分,这部分包括DAO接口、DAO接口实现类Mapper、POJO实体类、SQL执行Executor类、SqlSession类。

一个用户登录业务访问数据库流程如下:用户通过JSP填写登录账号和密码后,JSP会发送登录请求到指定的Controller类,Controller类收到请求后,会调用登录业务类(Service类),登录业务类调用DAO类的登录接口,因为该接口被Mapper类实现,因此Mapper类的登录SQL代码会被执行,真正执行SQL代码的是Executor类,它创建SqlSession对象,由SqlSession对象访问数据库的用户表,并将访问结果返回给Mapper,Mapper类会根据接口的返回类型返回数据到登录业务类。

DAO接口声明了访问数据库的具体操作方法,在不对外暴露数据库访问细节的前提下提供数据库的增删改查方法,它不负责增删改查方法的具体实现,方法的具体实现由Mapper负责。这样做的好处时当数据库访问细节发生变化时,不会影响到业务逻辑类的改动。例如,当数据库访问细节发生变化时,只需修改Mapper代码就可以了,而Mapper代码是XML文件,因此无需重新编译整个系统。假如实现细节放在DAO类中,就需要修改DAO类的代码,修改DAO类的代码显然会影响到Service类的代码,即使没有影响,也需要重新编译整个系统。DAO接口由MyBaits自动生成,无需手动编写DAO接口代码。

Mapper是DAO的实现类,Mapper不是Java类,而是一个XML文件,访问数据库的SQL语句都是在Mapper中实现的,这些Mapper代码不需要你手动编写,完全由MyBaits自动生成。

POJO是实体类,主要是需要数据传递和序列化的类。例如与数据库表对应的Java类。POJO类也不需要手动编写代码,POJO类完全由MyBaits自动生成。

Exectuor类是执行SQL语句的类,Mapper所有的SQL语句都通过Exectuor类来执行,Exectuor类会创建一个SqlSession完成对数据库的操作。

Mybatis简单体现在开发人员建立数据库后,可以使用Mybatis自身提供的插件自动生成上图虚线框中的DAO接口类、Mapper实现类、POJO实体类的代码,开发人员不需要手动编写这些代码。只有在特殊SQL查询需求的情况下,才会扩展这些代码。下图是Mybatis代码自动生成原理图。

image.png

图2 Mybaits代码自动生成原理图

Mybatis代码自动生成插件需要从配置文件中读取数据库的访问地址、登录账号和密码,还需要从配置文件中读取数据库的哪些表需要生成POJO类、DAO接口类和Mapper实现类,以及这些类存储到什么位置。

图 3 Mybaits代码自动生成配置文件

Mybatis入门程序

1、需求

实现以下功能:

  • 根据用户id查询一个用户信息
  • 根据用户名称模糊查询用户信息列表
  • 添加用户
  • 更新用户
  • 删除用户

2、环境

java 环境 :jdk1.8.0_77

开发工具 : IDEA 2016.1

数据库 : MySQL 5.7

Mybatis 运行环境( jar 包)

MySQL 驱动包

其他依赖包

3、 log4j.properties

在classpath下创建log4j.properties如下:

# Global logging configuration
#在开发环境日志级别要设置为DEBUG、生产环境要设置为INFO或者ERROR
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

Mybatis默认使用log4j作为输出日志信息。

4、工程结构

image

db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///mybatis
jdbc.username=root
jdbc.password=root

5、SqlMapConfig.xml

配置 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>
    <properties resource="db.properties"></properties>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <package name="com.mapper"></package>
    </mappers>
</configuration>

6、创建domain类

domain 类作为 mybatis 进行 sql 映射使用,po 类通常与数据库表对应,User.java 如下:

package com.company.domain;

import java.util.Date;

/**
 * Created by Administrator on 2017/10/21.
 */
public class User {
    private int id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

Mybatis 的 mapper 接口

思路

程序员需要编写mapper接口(相当于Dao接口,增删改查操作)
程序员需要编写 mapper.xml 映射文件,需遵循一些开发规范,mybatis 可以自动生成 mapper 接口类代理对象。

开发规范:

1.在 mapper.xml 中 namespace 等于 mapper 接口地址(所在包名的全路径)
<mapper namespace="com.mapper.UserMapper"></mapper>
2.在 xxxmapper.java 接口中的方法名要与 xxxMapper.xml 中 statement 的 id 一致。
3.在 xxxmapper.java 接口中的输入参数类型要与 xxxMapper.xml 中 statement 的 parameterType 指定的参数类型一致。
4.在 xxxmapper.java 接口中的返回值类型要与 xxxMapper.xml 中 statement 的 resultType 指定的类型一致。
5.接口文件名要与xml映射文件名一致(UserMapper.java和UserMapper.xml)

7、根据用户 id(主键)查询用户信息

定义Mapper接口

public interface UserMapper {
    public User findUserById(int id);
}

定义UserMapper.xml

<?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="com.mapper.UserMapper">
    <select id="findUserById" parameterType="int" resultType="com.domain.User">
        select * from user where id = #{value}
    </select>
</mapper>

主方法测试

    public static void main(String[] args) throws IOException {
        //创建sqlSessionFactory
        //Mybatis 配置文件
        String resource = "SqlMapConfig.xml";
        //得到配置文件流
        InputStream inputStream = Resources.getResourceAsStream(resource);
        //创建会话工厂,传入Mybatis的配置文件信息
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //创建usermapper对象,mybatis自动生成代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        //调用UserMapper的方法
        User user = userMapper.findUserById(1);
        System.out.println(user.getUsername());
    }

parameterType:指定输入参数类型,mybatis 从输入对象中获取参数值拼接在 sql 中。
resultType:指定输出结果类型,mybatis 将 sql 查询结果的一行记录数据映射为 resultType 指定类型的对象。

Sqlsession 的使用范围

SqlSession 中封装了对数据库的操作,如:查询、插入、更新、删除等。

通过 SqlSessionFactory 创建 SqlSession,而 SqlSessionFactory 是通过 SqlSessionFactoryBuilder 进行创建。

1、SqlSessionFactoryBuilder

SqlSessionFactoryBuilder 用于创建 SqlSessionFacoty,SqlSessionFacoty 一旦创建完成就不需要SqlSessionFactoryBuilder 了,因为 SqlSession 是通过 SqlSessionFactory 生产,所以可以将SqlSessionFactoryBuilder 当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。

2、SqlSessionFactory

SqlSessionFactory 是一个接口,接口中定义了 openSession 的不同重载方法,SqlSessionFactory 的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理 SqlSessionFactory。

3、SqlSession

SqlSession 是一个面向用户的接口, sqlSession 中定义了数据库操作,默认使用 DefaultSqlSession 实现类。

单例模式的SqlSessionFactory

public class SqlSessionFactoryUtil {
    //首先创建静态成员变量sqlSessionFactory,静态变量被所有的对象所共享。
    public static SqlSessionFactory sqlSessionFactory = null;
    public static SqlSessionFactory getSqlSessionFactory() {
        //如果sqlSessionFactory没有被创建就读取全局配置文件,假如已经被创建过了,就使用已经存在的sqlsessionfactory。
        //这样就有了单例模式的效果
        if(sqlSessionFactory==null){
            String resource = "SqlMapConfig.xml";
            try {
                Reader reader = Resources.getResourceAsReader(resource);
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return sqlSessionFactory;
    }
}

主方法测试变为:

    public static void main(String[] args) throws IOException {
        //创建sqlSessionFactory
        SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //创建usermapper对象,mybatis自动生成代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        //调用UserMapper的方法
        User user = userMapper.findUserById(1);
        System.out.println(user.getUsername());
    }

自定义别名:

在 SqlMapConfig.xml 中配置:(设置别名)

<?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>
    <properties resource="db.properties"></properties>
    <typeAliases>
        <!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) -->
        <package name="com.domain"/>
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <package name="com.mapper"></package>
    </mappers>
</configuration>

查找全部用户

UserMapper.java

public interface UserMapper {
    public User findUserById(int id);

    public List<User> findAllUsers();
    //添加用户信息
    public int addUser(User user);

    //删除用户信息
    public int deleteUser(int id);

    public int updateUserById(User user);
}

UserMapper.xml

<?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="com.mapper.UserMapper">
    <select id="findUserById" parameterType="int" resultType="User">
        select * from user where id = #{id}
    </select>
    <select id="findAllUsers" resultType="User">
        select * from user
    </select>
</mapper>

主方法测试

public static void main(String[] args) throws IOException {
        //创建sqlSessionFactory
        SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //创建usermapper对象,mybatis自动生成代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        //调用UserMapper的方法
//        User user = userMapper.findUserById(1);
//        System.out.println(user.getUsername());
        List<User> userList = userMapper.findAllUsers();
        for(User user : userList)
        {
            System.out.println(user.getUsername());
        }
    }

虽然 findAllUsers()的返回值类型是List<User>,xml文件中resultType="User"即可。

新增用户

 <insert id="addUser" parameterType="User" >
        <selectKey keyProperty="id" order="AFTER" resultType="int">
            select LAST_INSERT_ID()
        </selectKey>
        insert into user(username, birthday, sex, address)
        values(#{username}, #{birthday}, #{sex}, #{address})
    </insert>

主函数

   User user = new User();
        SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd");
        user.setUsername("田志");
        user.setSex("男");
        user.setBirthday(sdf.parse("2016-11-29"));
        user.setAddress("江西南昌");
        userMapper.addUser(user);
        System.out.println(user.getId());
        sqlSession.commit();

增删改操作需要 sqlSession.commit();

自增主键返回

MySQL 自增主键:执行 insert 提交之前自动生成一个自增主键,通过 MySQL 函数获取到刚插入记录的自增主键: LAST_INSERT_ID() ,是在 insert 函数之后调用。

删除用户

  <delete id="deleteUser" parameterType="int">
        delete from user where user.id = #{id}
    </delete>

     userMapper.deleteUser(1);
        sqlSession.commit();

更新用户

    <update id="updateUserById" parameterType="User">
        update user set username = #{username}, birthday = #{birthday}, sex = #{sex}, address = #{address} where user.id = #{id}
    </update>

    SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd");

        User user = new User();
        //根据id更新用户信息
        user.setId(24);
        user.setUsername("张四风2");
        user.setBirthday(sdf.parse("2015-01-12"));
        user.setSex("女");
        user.setAddress("上海黄埔");

        userMapper.updateUserById(user);

        //提交事务
        sqlSession.commit();

模糊查找用户

    <select id="findUserList" parameterType="User" resultType="User">
        select * from user where user.sex = #{sex} and user.username like #{username}
    </select>

 User user = new User();
        user.setSex("1");
        user.setUsername("%张%");

        //调用UserMapper的方法
        List<User> list = userMapper.findUserList(user);

        for(User u : list)
        {
            System.out.println(u.getUsername());
        }

查找user表记录数

    <select id="findUserCount" resultType="int">
        select count(*) from user
    </select>

      int count = userMapper.findUserCount();
        System.out.println(count);

动态 SQL

通过mybatis提供的各种标签方法实现动态拼接sql。

 <select id="findUserList2" parameterType="User" resultType="User">
        select * from user
        <!--where可以自动的去掉条件中的第一个and-->
        <where>

                <if test="sex != null and sex != ''">
                    and user.sex = #{sex}
                </if>
                <if test="username != null">
                    and user.username like  #{username}
                </if>

        </where>
    </select>

测试代码:因为设置了动态的sql,如果不设置某个值,那么条件就不会拼接在sql上

所以我们就注释掉设置username的语句

        User user = new User();
//        user.setSex("1");
        user.setUsername("%张%");

        //调用UserMapper的方法
        List<User> list = userMapper.findUserList2(user);

        for(User u : list)
        {
            System.out.println(u.getUsername());
        }

Sql 片段

通过上面的其实看到在 where sql语句中有很多重复代码,我们可以将其抽取出来,组成一个sql片段,其他的statement就可以引用这个sql片段,利于系统的开发。

这里我们就拿上边sql 中的where定义一个sq片段如下:

 <sql id="query_user_where">
        <if test="sex != null and sex != ''">
            and user.sex = #{sex}
        </if>
        <if test="username != null">
            and user.username like  #{username}
        </if>
    </sql>

那么我们该怎样引用这个sql片段呢?如下:

select * from user
        <where>
        <!--refid: 指定sql片段的id,如果是写在其他的mapper文件中,则需要在前面加上namespace-->
            <include refid="query_user_where"/>
        </where>

多表连接

再创建一个订单信息表

CREATE TABLE `orders` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL COMMENT '下单用户id',
  `number` varchar(32) NOT NULL COMMENT '订单号',
  `createtime` datetime NOT NULL COMMENT '创建订单时间',
  `note` varchar(100) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`id`),
  KEY `FK_orders_1` (`user_id`),
  CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of orders
-- ----------------------------
INSERT INTO `orders` VALUES ('3', '1', '1000010', '2015-02-04 13:22:35', null);
INSERT INTO `orders` VALUES ('4', '1', '1000011', '2015-02-03 13:22:41', null);
INSERT INTO `orders` VALUES ('5', '10', '1000012', '2015-02-12 16:13:23', null);

    public List<Map<String,Object>> getAllOrderInfo();

    <select id="getAllOrderInfo" resultType="map">
      select orders.number,user.username from orders
join user on orders.user_id = user.id
    </select>

       List<Map<String,Object>> mapList = userMapper.getAllOrderInfo();
        for(Map<String,Object> map : mapList)
        {
            System.out.println("---------------");
            for(Map.Entry<String,Object> entry : map.entrySet())
            {
                System.out.println(entry.getKey()+" "+entry.getValue());
            }

        }

代码

案例代码

代码自动生成

利用MyBatis生成器自动生成实体类、DAO接口和Mapping映射文件。这样可以大大节约开发时间,将生成的代码copy到项目工程中即可。

要想实现代码的自动生成,首先要下载一个工具:http://download.csdn.net/detail/u010608551/9434523,下载后解压zip文件,解压后的目录应该是如下的效果:

image

其中有mybatis框架的jar包,数据库驱动程序jar包以及MyBatis生成器jar包。其中的generatorConfig.xml是需要我们来配置的文件,配置如下:

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE generatorConfiguration  
  PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"  
  "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">  
<generatorConfiguration>  
<!-- 数据库驱动-->  
    <classPathEntry  location="mysql-connector-java-5.1.25-bin.jar"/>  
    <context id="DB2Tables"  targetRuntime="MyBatis3">  
        <commentGenerator>  
            <property name="suppressDate" value="true"/>  
            <!-- 是否去除自动生成的注释 true:是 : false:否 -->  
            <property name="suppressAllComments" value="true"/>  
        </commentGenerator>  
        <!--数据库链接URL,用户名、密码 -->  
        <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/test" userId="root" password="root">  
        </jdbcConnection>  
        <javaTypeResolver>  
            <property name="forceBigDecimals" value="false"/>  
        </javaTypeResolver>  
        <!-- 生成模型的包名和位置-->  
        <javaModelGenerator targetPackage="test.domain" targetProject="src">  
            <property name="enableSubPackages" value="true"/>  
            <property name="trimStrings" value="true"/>  
        </javaModelGenerator>  
        <!-- 生成映射文件的包名和位置-->  
        <sqlMapGenerator targetPackage="test.mapping" targetProject="src">  
            <property name="enableSubPackages" value="true"/>  
        </sqlMapGenerator>  
        <!-- 生成DAO的包名和位置-->  
        <javaClientGenerator type="XMLMAPPER" targetPackage="test.IDao" targetProject="src">  
            <property name="enableSubPackages" value="true"/>  
        </javaClientGenerator>  
        <!-- 要生成的表 tableName是数据库中的表名或视图名 domainObjectName是实体类名-->  
        <table tableName="emp" domainObjectName="Emp" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
    </context>  
</generatorConfiguration>

其中的数据库名称,用户名,密码以及表表根据自己的具体情况来修改,配置中的targetProject是目标文件夹,不会自动生成,需要自己创建。

配置文件写好以后,打开cmd,将目录切换到lib目录下,执行脚本:java -jar mybatis-generator-core-1.3.2.jar -configfile generatorConfig.xml -overwrite

然后就可以在src目录下找到相应的文件,每个数据库表都会对应三个文件(实体类、接口、配置文件)。

image
image

成功根本没有什么秘诀可言,如果真是有的话,就是两个:第一个就是坚持到底,永不放弃;第二个是当你想放弃的时候,回过头来看看第一个秘诀:坚持到底,永不放弃

Intelij安装mybatis代码自动生成器插件

参考
https://www.jianshu.com/p/d019c9880d25

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

推荐阅读更多精彩内容

  • MyBatis 是一款优秀的持久层框架,它支持定制化 SQL(灵活)、存储过程(PLSQL模块化的组件,数据库的一...
    _FireFly_阅读 427评论 0 0
  • MyBatis 是一款优秀的持久层框架,它支持定制化 SQL(灵活)、存储过程(PLSQL模块化的组件,数据库的一...
    极课编程阅读 1,130评论 0 18
  • Mybatis 创建数据库 Mybatis框架原理(掌握) 1、Mybatis 是什么? Mybatis 是一个持...
    __豆约翰__阅读 1,374评论 1 11
  • MyBatis 是一款优秀的持久层框架,它支持定制化 SQL(灵活)、存储过程(PLSQL模块化的组件,数据库的一...
    G_慧慧阅读 272评论 0 0
  • Mybatis 创建数据库 Mybatis框架原理(掌握) 1、Mybatis 是什么? Mybatis 是一个持...
    __元昊__阅读 347评论 0 0