Spring Boot 中使用 tkMapper

说明:基于 MyBatis 有很多第三方功能插件,这些插件可以完成数据操作方法的封装、数据库逆向工程的生成等。 tkMapperMyBatis-plus 都是基于 MyBatis 提供的第三方插件,功能类似,下面介绍 tkMapper 的使用。

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

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

tkMapper 的使用需要基于 MyBatis。

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

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;
@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;

}

注意:创建的 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 {
}

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


    junit
    junit
    test

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

写测试类进行测试:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringbootTkMapperDemoApplication.class) //启动类.class
public 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);
    }
}
  • insert:普通添加
  • insertUseGeneratedKeys:可返回自增 id 的添加
  • updateByPrimaryKey:根据主键修改
  • deleteByPrimaryKey:根据主键删除
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringbootTkMapperDemoApplication.class) //启动类.class
public 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:其实还有根据自定义条件修改或删除的方法(使用方法参考带条件的查询示例)

  • selectAll:查所有
  • selectByPrimaryKey:根据主键查所有
  • selectByExample:根据条件查所有
  • selectByRowBounds:分页查询
  • selectByExampleAndRowBounds:带条件的分页查询
  • selectCount:查总记录数
  • selectCountByExample:根据条件查总记录数
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringbootTkMapperDemoApplication.class) //启动类.class
public 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);
    }
}

说明:所有的关联/多表查询都可以由多个单表查询组成
关联/多表查询实现方式:
方式一:多次使用单表查询,然后封装数据
方式二:自定义查询方法和 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) //启动类.class
public 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);
    }
}

anno desc @Id 标记该字段为数据库主键 @KeySql(useGeneratedKeys = true) 主键生成策略,使用 JDBC 的方式获取数据库自增的主键值 @Table(name = “country”) 表名 @Column(name = “user_name”) 数据库映射字段 @Transient 表明非数据库字段

T selectOne(T record)

根据实体中的属性进行查询,只能有一个返回值,有多个结果则抛出异常,查询条件使用等号

List select(T record)

根据实体中的属性值进行查询,查询条件使用等号

List selectAll()

查询全部结果

int selectCount(T record)

根据实体中的属性查询总数,查询条件使用等号

T selectByPrimaryKey(Object key)

根据 主键字段进行查询,方法参数必须包含完整的主键属性,查询条件使用等号

boolean existsWithPrimaryKey(Object key)

根据 主键字段查询总数,方法参数必须包含完整的主键属性,查询条件使用等号

List selectByExample(Object example)

根据example条件进行查询一条或多条数据

selectOneByExample(Object example)

根据example条件查询一条数据

selectCountByExample(Object example)

根据example条件查询记录数

List selectByExampleAndRowBounds(Object example, RowBounds rowBounds);

根据example条件和RowBounds进行分页查询

List selectByRowBounds(T record, RowBounds rowBounds);

根据实体属性和RowBounds进行分页查询

int insert(T record)

保存一个实体, 实体中缺省的属性也会保存,使用null保存而不是数据库默认值

int insertSelective(T record)

保存一个实体,null的属性不会保存,会使用数据库默认值,无默认值则使用null

int updateByPrimaryKey(T record)

根据主键更新实体全部字段, 实体中缺省的字段也会被更新,被更新为null

int updateByPrimaryKeySelective(T record)

根据主键更新属性不为null的值,实体中缺省的字段不会被更新

根据example条件更新实体record包含的全部属性, 实体中缺省的值也会被更新,更新为null

int updateByExampleSelective(@Param(“record”) T record, @Param(“example”) Object example)

根据example条件更新实体record包含的不是null的属性值, 实体中缺省的字段不会被更新

int delete(T record)

根据实体属性作为条件进行删除,查询条件使用等号

int deleteByPrimaryKey(object key)

根据 主键字段进行删除,方法参数必须包含完整的主键属性

int deleteByExample(Object example)

根据example条件删除数据

Example example = new Example(xxx.class);

method desc example.setOrderByClause(“字段名 DESCASC”) 添加升序排列条件,DESC 为降序 example.setDistinct(false) 是否去重 example.orderBy(“pid”) 排序,order by pid,默认为 ASC example.orderBy(“pid”).desc() 逆序排序 example.selectProperties(”id”, “pid”, …) 选择查询的列,select id , pid … example.excludeProperties(“name”, “icon”) 排除查询的列,结果不显示 example.and().andEqualTo(“id”, 4) 等值查询,and id = 4 example.and().andLike(“pid”, “%5%”) 模糊查询:and pid like %5% example.and().andBetween(“id”, 5, 8) 区间查询:and (id betewwn 5 and 8) … …

Example.Criteria criteria = example.createCriteria();

method desc criteria.andIsNull() 字段为 null criteria.andNotNull() 字段不为 null criteria.andEqualTo() 字段等于 criteria.andNotEqualTo() 字段不等于 criteria.andGreaterThan() 字段大于 criteria.andGreaterThanOrEqualTo() 字段大于等于 criteria.andLessThan() 字段小于 criteria.andLessThanOrEqualTo() 字段小于等于 criteria.andIn() 字段在 List 中 criteria.andNotIn() 字段不在 List 中 criteria.andLike(“%” + value + “%”) 字段为 value 的模糊查询条件 criteria.andNotLike(“%” + value + “%”) 字段不为 value 的模糊查询条件 criteria.andBetween(value1, value2) 字段在 value1 和 value2 之间 criteria.andNotBetween(value1, value2) 字段不在 value1 和 value2 之间 … …

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

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

Original: https://www.cnblogs.com/luisblog/p/16875672.html
Author: luis林威
Title: Spring Boot 中使用 tkMapper

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/798937/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球