说明:基于 MyBatis 有很多第三方功能插件,这些插件可以完成数据操作方法的封装、数据库逆向工程的生成等。

tkMapperMyBatis-plus 都是基于 MyBatis 提供的第三方插件,功能类似,下面介绍 tkMapper 的使用。

简介

tkMapper 就是一个 MyBatis 插件,基于 MyBatis 提供很多工具,提高开发效率,主要有以下两个功能。

  • 提供针对单表通用的数据库操作方法
  • 逆向工程(根据数据表自动生成实体类、Dao 接口、Mapper 映射文件)

MyBatis 基础环境

tkMapper 的使用需要基于 MyBatis。

  1. 创建 Spring Boot 项目,选中 Lombok、Spring Web、MyBatis Framework、MySQL Driver 依赖

  2. application.yml 配置文件中配置相关信息

    spring:  datasource:    driver-class-name: com.mysql.jdbc.Driver    url: jdbc:mysql://localhost:3306/springdb?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8    username: root    password: luismybatis:  type-aliases-package: com.luis.beans  mapper-locations: classpath:mappers/*Mapper.xml

    注意:配置后,手动创建 beans 和 mappers 文件夹

  3. 创建 dao 文件夹,在启动类上添加 dao 的包扫描器 @MapperScan(basePackages = {"com.luis.dao"})

tkMapper 环境搭建

  1. 添加依赖

        tk.mybatis    mapper-spring-boot-starter    2.1.5

    如果自己在 maven 仓库中搜索,注意搜索关键词:mapper starter

    PS:添加后,注意手动刷新 pom

  2. 更换启动类上 dao 包的包扫描器来源,不使用原先的 @MapperScan,要使用新添加的 tkMapper 的 @MapperScan

    import tk.mybatis.spring.annotation.MapperScan;@SpringBootApplication@MapperScan(basePackages = {"com.luis.dao"}) //使用tkMapper的包扫描器注解public class SpringbootTkMapperDemoApplication {    public static void main(String[] args) {        SpringApplication.run(SpringbootTkMapperDemoApplication.class, args);    }}

    PS:注意注解的包来源 import tk.mybatis.spring.annotation.MapperScan

  3. 以上,tkMapper 环境已经搭建完成

tkMapper 对数据的通用操作

tkMapper 提供针对单表通用的数据库操作方法。

数据准备1. 创建数据库表

DROP TABLE IF EXISTS `users`;CREATE TABLE `users`  (  `user_id` int(11) NOT NULL AUTO_INCREMENT,  `user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,  `user_pwd` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,  `user_realname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,  `user_img` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,  PRIMARY KEY (`user_id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Compact;

2. 创建实体类

@Data@NoArgsConstructor@AllArgsConstructor@Table(name = "users") //数据库表名和实体类类名不一致需要指定映射关系!public class User {    @Id //指定主键    private Integer userId;    private String userName;    private String userPwd;    private String userRealname;    private String userImg;}

3. 创建 Dao 接口【重点】

注意:创建的 Dao 接口需要继承 tkMapper 中提供的 MapperMySqlMapper 两个接口,这两个接口提供了对单表的通用操作。

public interface UserDao extends Mapper, MySqlMapper {}

可选优化策略【建议使用】:

如果不想每次创建 dao 接口时都继承 tkMapper 中的两个接口,可以自己写一个通用的接口模板,只需要让这个通用的接口模板继承 tkMapper 中的两个接口,然后自己创建的 dao 接口只需要继承这个通用的接口模板即可!

但是,需要注意的是,这个通用的接口模板千万不能写在 dao 目录下!因为 dao 目录下的接口会被扫描到,有固定的功能用处;而我们自定义的通用接口模板只是为了继承,没有其他特殊功能!

使用示例:

1、可在 dao 目录同级创建 general 目录,在 general 目录下创建 GeneralDao 接口,并继承 tkMapper 中的两个接口。

package com.luis.general;import tk.mybatis.mapper.common.Mapper;import tk.mybatis.mapper.common.MySqlMapper;/** * @Author: Luis * @date: 2022/11/9 14:39 * @description: 自定义的通用接口模板 */public interface GeneralDao extends Mapper, MySqlMapper {}

2、创建 dao 接口,继承 GeneralDao 即可!

public interface UserDao extends GeneralDao {}

4. 测试

添加 Junit 和 springboot test 两个测试依赖:

    junit    junit    test    org.springframework.boot    spring-boot-starter-test

写测试类进行测试:

@RunWith(SpringRunner.class)@SpringBootTest(classes = SpringbootTkMapperDemoApplication.class) //启动类.classpublic class UserDaoTest {    @Autowired    private UserDao userDao; //如果爆红线不用管(或Dao接口上添加@Repository注解)    @Test    public void test() {        User user = new User();        user.setUserName("mike");        user.setUserPwd("123");        user.setUserRealname("zhangsan");        user.setUserImg("user/default.jpg");        int i = userDao.insert(user);        System.out.println("========> i = " + i);    }}

tkMapper 常用方法之增删改

  • insert:普通添加
  • insertUseGeneratedKeys:可返回自增 id 的添加
  • updateByPrimaryKey:根据主键修改
  • deleteByPrimaryKey:根据主键删除
@RunWith(SpringRunner.class)@SpringBootTest(classes = SpringbootTkMapperDemoApplication.class) //启动类.classpublic class UserDaoTest {    @Autowired    private UserDao userDao; //如果爆红线不用管(或Dao接口上添加@Repository注解)    @Test    public void testInsert() {        User user = new User();        user.setUserName("juno4");        user.setUserPwd("321");        user.setUserRealname("lin");        user.setUserImg("user/default.jpg");        /**         * insert: 添加(自增的id不会返回)         */        int i = userDao.insert(user);        System.out.println("========> i = " + i);        System.out.println(user.getUserId()); //null    }    @Test    public void testInsertUseGeneratedKeys() {        User user = new User();        user.setUserName("juno3");        user.setUserPwd("321");        user.setUserRealname("lin");        user.setUserImg("user/default.jpg");        /**         * insertUseGeneratedKeys: 添加(自增的id可以返回)         * 注意:         *  1. 数据库中主键字段需要设置为自增         *  2. 实体类中主键属性需要使用@Id注解指定;并且需要使用包装类型Integer,不要使用int         */        int i = userDao.insertUseGeneratedKeys(user);        System.out.println("========> i = " + i);        System.out.println(user.getUserId()); //10    }    @Test    public void testUpdateByPrimaryKey() {        User user = new User();        user.setUserId(10); //必须指定要修改的id        user.setUserName("juno new");        user.setUserPwd("000");        user.setUserRealname("lin new");        user.setUserImg("new.jpg");        /**         * updateByPrimaryKey:根据主键修改         */        int i = userDao.updateByPrimaryKey(user);        System.out.println("========> i = " + i);        System.out.println(user);    }    @Test    public void testDeleteByPrimaryKey() {        /**         * deleteByPrimaryKey:根据主键删除         */        int i = userDao.deleteByPrimaryKey(9);        System.out.println("========> i = " + i);    }}

PS:其实还有根据自定义条件修改或删除的方法(使用方法参考带条件的查询示例)

tkMapper 常用方法之查询

  • selectAll:查所有
  • selectByPrimaryKey:根据主键查所有
  • selectByExample:根据条件查所有
  • selectByRowBounds:分页查询
  • selectByExampleAndRowBounds:带条件的分页查询
  • selectCount:查总记录数
  • selectCountByExample:根据条件查总记录数
@RunWith(SpringRunner.class)@SpringBootTest(classes = SpringbootTkMapperDemoApplication.class) //启动类.classpublic class UserDaoTest {    @Autowired    private UserDao userDao; //如果爆红线不用管(或Dao接口上添加@Repository注解)    @Test    public void testSelectAll() {        /**         * selectAll:查询所有         */        List users = userDao.selectAll();        for (User user : users) {            System.out.println(user);        }    }    @Test    public void testSelectByPrimaryKey() {        /**         * selectByPrimaryKey:根据主键查询         */        User user = userDao.selectByPrimaryKey(10);        System.out.println(user);    }    @Test    public void testSelectByExample() {        //封装查询条件        Example example = new Example(User.class);        Example.Criteria criteria = example.createCriteria();        //条件信息(根据Criteria对象的各种方法进行设置)        criteria.andEqualTo("userRealname", "lin");        // criteria.orEqualTo("userPwd", "123");        // criteria.andLike("userName", "%i%");        /**         * selectByPrimaryKey:根据条件查询(PS:根据条件修改或删除与此类似)         *      注意:需要设置查询条件信息,并传入条件对象         */        List users = userDao.selectByExample(example);        for (User user : users) {            System.out.println("========> " + user);        }    }    @Test    public void testSelectByRowBounds() {        //分页查询信息        int pageNum = 2; //第几页        int pageSize = 3; //每页显示多少行        int start = (pageNum - 1) * pageSize; //起始显示的下标        RowBounds rowBounds = new RowBounds(start, pageSize);        /**         * selectByRowBounds:查所有的分页查询         */        List users = userDao.selectByRowBounds(new User(), rowBounds);        for (User user : users) {            System.out.println("========> " + user);        }        /**         * selectCount:查询总记录数         */        int count = userDao.selectCount(new User());        System.out.println("========> count = " + count);    }    @Test    public void testSelectByExampleAndRowBounds() {        //封装查询条件        Example example = new Example(User.class);        Example.Criteria criteria = example.createCriteria();        criteria.andEqualTo("userRealname", "lin");        //分页查询信息        int pageNum = 2; //第几页        int pageSize = 2; //每页显示多少行        int start = (pageNum - 1) * pageSize; //起始显示的下标        RowBounds rowBounds = new RowBounds(start, pageSize);        /**         * selectByExampleAndRowBounds:带条件的分页查询         */        List users = userDao.selectByExampleAndRowBounds(example, rowBounds);        for (User user : users) {            System.out.println("========> " + user);        }        /**         * selectCountByExample:根据条件查询总记录数         */        int count = userDao.selectCountByExample(example);        System.out.println("========> count = " + count);    }}

tkMapper 关联/多表查询

说明:所有的关联/多表查询都可以由多个单表查询组成

关联/多表查询实现方式:

方式一:多次使用单表查询,然后封装数据

方式二:自定义查询方法和 SQL

情景:基于以上的用户表,新添加一个订单表 orders,订单表中有订单信息,但是也有用户 id;

要求:在查询用户表的同时还要查询出用户的订单信息,这就涉及到了两张表的查询。

具体业务要求:根据用户名查询用户的所有信息,包括订单信息。

数据准备

新建订单表 orders:

DROP TABLE IF EXISTS `orders`;CREATE TABLE `orders`  (  `order_id` int(11) NOT NULL AUTO_INCREMENT,  `user_id` int(11) NOT NULL,  `receiver_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,  `receiver_mobile` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,  `receiver_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,  PRIMARY KEY (`order_id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Compact;INSERT INTO `orders` VALUES (1, 1, 'luis', '13344445555', '湖北武汉');

新建实体类 Order:

@Data@NoArgsConstructor@AllArgsConstructor@Table(name = "orders")public class Order {    @Id    private Integer orderId;    private Integer userId;    private String receiverName;    private String receiverMobile;    private String receiverAddress;}

新建 dao 接口:

注意,此处 dao 接口继承的是自定义的通用接口模板,相关说明参见之前创建示例 UserDao 的步骤。

也可以直接继承 tkMapper 的两个接口。(注意灵活运用!)

public interface OrderDao extends GeneralDao {}

说明:进行关联/多表查询前,需要修改下之前的 User 实体类,在实体类中需要添加一个订单的字段,以便查询出用户所关联的订单信息。

@Data@NoArgsConstructor@AllArgsConstructor@Table(name = "users") //数据库表名和实体类类名不一致需要指定映射关系!public class User {    @Id //指定主键    private Integer userId;    private String userName;    private String userPwd;    private String userRealname;    private String userImg;        //订单    private List orderList;}

方式一:多次单表查询

@RunWith(SpringRunner.class)@SpringBootTest(classes = SpringbootTkMapperDemoApplication.class) //启动类.classpublic class UserDaoTest {    @Autowired    private UserDao userDao; //如果爆红线不用管(或Dao接口上添加@Repository注解)    @Autowired    private OrderDao orderDao;    @Test    public void test() {        //根据用户名查询用户信息        Example example = new Example(User.class);        Example.Criteria criteria = example.createCriteria();        criteria.andEqualTo("userName", "luis");        //条件查询        List users = userDao.selectByExample(example);        User user = users.get(0);        //根据用户id查询订单信息        Example example1 = new Example(Order.class);        Example.Criteria criteria1 = example.createCriteria();        criteria.andEqualTo("userId", user.getUserId());        //条件查询        List orders = orderDao.selectByExample(example1);        //将查询到的订单信息设置到user中        user.setOrderList(orders);        System.out.println("========> " + user);    }}    

方式二:自定义连接查询

  1. UserDao 接口中新建查询方法

    public interface UserDao extends GeneralDao {    public User selectByUserName(String userName);}
  2. mappers 目录下创建对应的 UserMapper.xml 文件,自定义查询 SQL

                                                                                                                                                select u.user_id,u.user_name,u.user_pwd,u.user_realname,u.user_img,               o.order_id,o.user_id,o.receiver_name,o.receiver_mobile,o.receiver_address        from users u inner join orders o        on u.user_id = o.user_id;  
  3. 测试

    @RunWith(SpringRunner.class)@SpringBootTest(classes = SpringbootTkMapperDemoApplication.class) //启动类.classpublic class UserDaoTest {    @Autowired    private UserDao userDao; //如果爆红线不用管(或Dao接口上添加@Repository注解)    @Autowired    private OrderDao orderDao;    @Test    public void test02() {        //使用自定义的查询方法        User user = userDao.selectByUserName("luis");        System.out.println("========> " + user);    }}    

逆向工程

所谓逆向工程,就是通过数据库表,来自动生成实体类、dao 接口和 mapper 文件。

需要注意的是,本逆向工程是最好配合 tkMapper 环境使用,因为,有一些配置和 tkMapper 相关,如生成的 dao 接口会继承自定义的通用接口模板,而该通用的接口模板就是继承了 tkMapper 中的两个接口,从而才能使用 tkMapper 提供的通用数据操作方法;还有,生成的实体类上的注解需要依赖 tkMapper 环境。

重要说明:本逆向工程使用的 mysql 版本是低版本 5.1.36!经测试,如果使用高版本如 8.xxx,很大概率会生成有问题!所以建议项目中统一使用低版本的 MySQL。

  1. 在 pom.xml 中 build 的 plugins 下添加下列生成器插件

        org.mybatis.generator    mybatis-generator-maven-plugin    1.3.6                            ${basedir}/src/main/resources/generator/GeneratorConfig.xml                                                mysql            mysql-connector-java            5.1.36                                    tk.mybatis            mapper            4.1.5            

    注意:推荐直接复制,但如果想自己在 maven 仓库中搜索,注意关键词:mybatis-generator-maven-plugin,并且,千万注意,你搜索到的肯定是依赖,而并非插件!此时,你只需要复制依赖的 gav 坐标,自己在 pom 中创建空 plugin 标签,将 gav 坐标复制进去即可!(如果相关依赖刷新添加失败,可以复制到 dependences 下,重新刷新添加试试,添加成功后复制回来即可)

  2. 注意查看项目中是否自定义有通用接口模板 GeneralDao,使其继承 tkMapper 的两个接口;如果没有,则在 dao 同级目录,创建 general 目录,在 general 目录下创建自定义通用接口模板 GeneralDao,继承 tkMapper 的两个接口;

    public interface GeneralDao extends Mapper, MySqlMapper {}
  3. resources/generator 下添加 GeneratorConfig.xml 生成器配置(创建并复制后改主要配置即可)

    主要需要配置:配置数据库连接、配置实体类存放路径、配置 XML 存放路径、配置 DAO 存放路径、配置 GeneralDao

    注意:默认配置是生成指定数据库中所有表,也可以自定义的指定只生成哪些表

        <!--    -->                                                                                                                                                            <!--            -->        
    <!-- --><!-- --><!--
    --><!-- --><!-- --><!--
    -->
  4. 打开 IDEA 右侧 Maven 窗口,找到项目–》Plugins–》mybatis-generator–》mybatis-generator:generate,双击执行逆向生成即可!

    示例图:

  5. 查看 beans、dao、mappers 目录下的生成情况,看生成的相关接口是否符合开发要求,根据情况可做相关修改,然后进行相关测试。

都看到最后了,右下角来个赞鸭!-.- 欢迎评论留言~