MyBatis-Plus框架

0 阅读11分钟

说明:Mybaits-Plus是Mybatis框架的升级,该框架提供了一系列API,用于操作数据,可以免受手搓SQL语句的痛苦。

一、使用

第一步:添加依赖

使用前,需先添加对应的依赖,建议使用最新的版本

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.2</version>
</dependency>

application.yml配置文件

# 1.数据源的配置
spring:
  # 数据库配置
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db_mybatis_plus
    username: root
    password: 123456
    
# 2.mybatis-plus配置
mybatis-plus:
  configuration:
    # 配置日志的实现类 stdOutImpl 输出到控制台
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.hzy</groupId>
    <artifactId>essay_mybatis_plus</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>
    
	<!--springboot-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.12</version>
        <relativePath/>
    </parent>

    <dependencies>
        <!--web依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!--druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.8</version>
        </dependency>

        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.2</version>
        </dependency>

        <!--数据库连接池-->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!--测试类-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.6</version>
        </dependency>
    </dependencies>

</project>

第二步:环境搭建

创建一张User表,注意ID设置为bigint类型

在这里插入图片描述

创建一个User实体类

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
    private Long id;
    private String userName;
    private String password;
    private String name;
    private Integer age;
    private String email;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
    private Integer del;
}

第三步:关联表与MyBatis-Plus

实体类中增加@TableName()注解,括号内填该实体类在数据中对应的表名称;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName("tb_user")
public class User implements Serializable {
    private Long id;
    private String userName;
    private String password;
    private String name;
    private Integer age;
    private String email;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
    private Integer del;
}

Mapper层继承BaseMapper类,尖括号内填该Mapper对应的实体类对象;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hzy.pojo.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper extends BaseMapper<User> {
}

第四步:测试

在测试类中,装配Mapper,使用属性名.的方式,查看是否有MyBatis-plus提供的API,有的话说明已经关联成功,此时就可以使用API对数据库进行增删改查操作 在这里插入图片描述

二、API

(1)添加数据

添加一条对象数据

    @Test
    public void insertTest(){
        User user = new User();
        user.setUserName("zhangsan");
        user.setPassword("123456");
        user.setName("张三");
        user.setAge(18);
        user.setEmail("zhangsan@gmail.com");
        userMapper.insert(user);
    }

在这里插入图片描述 需要注意:

1)这里的ID是MyBatis-Plus自动生成的,后面可以修改生成ID的策略;

2)不需要在配置中设置对象属性名(userName)和数据表字段名(user_name)允许驼峰命名,MyBatis-Plus会自动适配;

3)添加后的数据,会自动填充ID的,不需要考虑主键返回的问题;

(2)删除数据

在这里插入图片描述

    @Test
    public void deleteTest(){
        // 1.根据ID删除
        int i = userMapper.deleteById(1677652427726557186L);
        System.out.println(i);

        // 2.根据ID批量删除
        ArrayList<Long> ids = new ArrayList<>();
        ids.add(1L);
        ids.add(2L);
        ids.add(3L);
        userMapper.deleteBatchIds(ids);

        // 3.根据条件(Map)删除
        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("user_name","lisi");
        userMapper.deleteByMap(hashMap);

        // 4.根据条件(QueryWrapper)删除
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.gt("age",20);
        int j = userMapper.delete(wrapper);
        System.out.println("j = " + j);
    }

在这里插入图片描述 需要注意,条件删除使用Map,只能做等值判断,不能做比较判断,建议使用QueryWrapper

(3)修改数据

例如,将下面这条记录的name修改为小明;

在这里插入图片描述

    @Test
    public void updateTest() {

        // 1.根据ID修改
        User user1 = new User();
        user1.setId(1677657896868278273L);
        user1.setName("小明");
        userMapper.updateById(user1);

        // 2.根据条件(QueryWrapper)修改
        User user2 = new User();
        user2.setName("小明");

        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("id", 1677657896868278273L);
        userMapper.update(user2, wrapper);


        // 3.根据条件(UpdateWrapper)修改
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("user_name", "zhangsan");
        updateWrapper.set("name", "小明");
        userMapper.update(null, updateWrapper);

        // 4.使用lambda+方法引用简写代码
        userMapper.update(null, Wrappers.lambdaUpdate(User.class)
                .eq(User::getUserName,"zhangsan").set(User::getName,"小明"));
    }

其中eq是等值判断,其他的比较方法如下: 在这里插入图片描述

需要注意的是:

(1)使用ID修改记录,传入的对象需要设置ID;

(2)使用UpdateWrapper做条件修改,相较于QueryWrapper,前者可以在条件判断的同时设置修改后的值;

(4)查询数据

Mybatis-Plus中有丰富的查询API,如下,其中根据条件查询单条记录(2)和多条记录(5)较为常用;

    @Test
    public void selectTest() {
        // 1.根据ID查询:查询ID等于2的记录
        User user1 = userMapper.selectById(2L);
        System.out.println(user1);

        // 2.根据条件查询:查询user_name等于zhangsan的记录(常用)
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUserName,"zhangsan");
        User user2 = userMapper.selectOne(wrapper);
        System.out.println(user2);

        // 3.根据ID集合进行批量查询:查询id in (1,2,3)的记录
        List<Long> ids = new ArrayList<>();
        ids.add(1L);
        ids.add(2L);
        ids.add(3L);

        List<User> users = userMapper.selectBatchIds(ids);
        System.out.println(users);

        // 4.根据条件查询多条记录,但只返回首个字段,即主键的值:查询年龄为20的记录,返回这些集合的主键值
        List<Object> objects = userMapper.selectObjs(Wrappers.lambdaQuery(User.class).ge(User::getAge,20));
        System.out.println(objects);

        // 5.根据条件查询多条记录:查询年龄为20的所有记录(常用)
        List<User> userList = userMapper.selectList(Wrappers.lambdaQuery(User.class).ge(User::getAge,20));
        System.out.println(userList);

        // 6.根据条件查询总记录条数:条件为空,为查询所有记录条数
        Long count = userMapper.selectCount(null);

        // 7.模糊查询:统计user_name中以zh开头的记录
        Long likeCount = userMapper.selectCount(Wrappers.lambdaQuery(User.class).likeRight(User::getUserName, "zh"));
        System.out.println(likeCount);

        // 8.使用Map作为条件进行查询:查询user_name等于zhangsan的记录
        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("user_name", "zhangsan");
        List<User> selectByMap = userMapper.selectByMap(hashMap);
        System.out.println(selectByMap);

        // 9.把查询结果封装到Map中
        List<Map<String, Object>> maps = userMapper.selectMaps(Wrappers.emptyWrapper());
        for (Map<String, Object> map : maps) {
            System.out.println(map);
        }

        // 10.多条件查询1:查询年龄大于20岁,并且 user_name以zh开头的
        List<User> selectList = userMapper.selectList(Wrappers.lambdaQuery(User.class).gt(User::getAge, 20).likeRight(User::getUserName, "zh"));
        for (User user : selectList) {
            System.out.println(user);
        }

        // 11.多条件查询2:查询年龄小于25岁 或者 user_name包含zh的
        List<User> list = userMapper.selectList(Wrappers.lambdaQuery(User.class).lt(User::getAge, 25).like(User::getUserName, "zh"));
        for (User user : list) {
            System.out.println(user);
        }

        // 12.查询指定字段:查询ID等于10的记录的id、user_name字段
        User user = userMapper.selectOne(Wrappers.lambdaQuery(User.class).select(User::getId, User::getUserName).eq(User::getId, 10L));
        System.out.println(user);

        // 13.排序查询:查询年龄大于25岁的,并且按照年龄进行倒序
        List<User> users1 = userMapper.selectList(Wrappers.lambdaQuery(User.class).gt(User::getAge, 25).orderByDesc(User::getAge));
        for (User user3 : users1) {
            System.out.println(user3);
        }
    }

三、MyBatis-Plus的其他功能

Mybatis-Plus除了提供一套API外,还提供了一些附加功能;

(1)主键填充

可在实体类中,设置ID自动生成ID的策略,AUTO为数据库自动递增策略

@TableId(type = IdType.AUTO)
private Long id;

关于IdType的备选项,官网说明如下: 在这里插入图片描述

(2)数据填充

Mybatis-Plus提供了对添加数据、更新数据进行填充的功能,如用户字段create_time、update_time的值,可由Mybatis-Plus自动填充;

第一步:在对应字段上添加注解

    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;

第二步:创建配置类

可参考官网代码(baomidou.com/pages/4c6bc…

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;

/**
 * MyMetaObjectHandler 
 * 
 * 是Mybatis-Plus提供的一个接口
 */
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    /**
     * 插入操作 自动填充createTime、updateTime的值
     * @param metaObject 元对象 就是使用CURD时传入的对象
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        // 注意这里的数据类型要与JavaBean中对应属性的数据类型一致
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    }

    /**
     * 更新操作 自动修改updateTime的值
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    }
}

需要注意以下两点:

(1)自动填充未做非空校验:即添加的对象已设置了create_time、update_time的值,应该以传入的值为准,不再填充,可使用 Object fieldValue = getFieldValByName("fieldName", metaObject); 获取代理对象的字段值进行判断;

(2)自动填充的数据类型应该与JavaBean对象对应字段的数据类型一致,如create_time属性,JavaBean中类型是LocalDateTime,则自动填充的数据库类型也应该是LocalDateTime,而不能是LocalDate;

(3)逻辑删除

在实际业务中,如果用户注销账户,对于用户来说,是删除了账户有关的所有记录,如订单、好友列表等等,但对于后台管理端来说,该用户的数据已经产生了,已经在各种统计报表中存在。如果用户注销账户,也同步删除数据库中的相关数据,会造成报表数据有偏差。

所以,当用户注销账户时,对于数据库来说,会将该用户相关的表数据设置为“已删除”,而不会真正删除。具体实现为,在表中设置一个“标识判断”,表示该条记录是否为业务层面上的“已删除数据”或者“正常数据”,这种方式称为逻辑删除。

如上面tb_user表中的最后一个字段(del),可在对应的JavaBean中,在del属性上设置逻辑删除注解;表示“正常数据”值为0,“已删除数据”值为1。设置后,后续所有对数据库的操作,会自动考虑,如delete方法只会更新该标识字段,select方法会自动追加判断该数据是否为“已删除数据”。

    @TableLogic(value = "0",delval = "1")
    private Integer del;

在这里插入图片描述

需要注意以下两点:

(1)在数据库表中,该字段不能为空,只能有设置的0、1这两个值,所以建议该字段创建时设置默认值(当然默认值应该为“正常数据”);

(2)该功能的实现,实际上就是在SQL语句后面追加了对数据标识字段的判断,如“and del = 0”。所以当查询结果为null时,应考虑查询的该条记录标识字段是否设置为了“已删除”; 在这里插入图片描述

(4)属性排除

当我们设置了一个JavaBean,该JavaBean中存在一个属性,该属性不能和数据库表字段一一对应时,我们使用对应的API去查询数据库时,由于该属性值不能在数据库表字段中找到,查询会报错。

比如,在上面的User类中增加一个orders属性,数据类型为List,表示该用户的订单;

    private List<Order> orders;

查询会报错,因为该属性在数据库表中并没有与之对应的字段 在这里插入图片描述

此时,我们可以用MyBatis-Plus中的属性排除,在对应属性上设置@TableField(exist = false)注解,排除掉该属性,让查询记录时不查询该字段;

    @TableField(exist = false)
    private List<Order> orders;

在这里插入图片描述

(5)Service增强

当一个请求非常简单,没有复杂的业务逻辑时,可以使用MyBatis-Plus提供的Service增强技术,可不再Service层中编写对应的方法,直接在Controller层中,使用Service对象,调用到Mapper层中的方法。具体操作如下:

第一步:Service接口继承IService

在Service接口中,继承MyBatis-Plus的IService类,泛型填对应的JavaBean;

import com.baomidou.mybatisplus.extension.service.IService;
import com.hzy.pojo.User;

public interface UserService extends IService<User> {
}

第二步:Service实现类继承ServiceImpl

在Service实现类中,继承MyBatis-Plus的ServiceImpl类,并设置泛型,泛型内分别写对应Mapper和JavaBean;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzy.mapper.UserMapper;
import com.hzy.pojo.User;
import com.hzy.service.UserService;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}

第三步:Controller层中使用

此时,Service层中不需要写方法,就可以使用对数据库操作的API

import com.hzy.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/test")
    public String test() {
        return userService.getById(2L).toString();
    }
}

(6)分页查询

使用MyBatis-Plus的分页功能,先需要创建配置类;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Mybatis-Plus配置类
 */
@Configuration
public class MybatisConfig {

    /**
     * 手动装配Bean对象
     * @return
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        // 创建MybatisPlusInterceptor
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

        // 设置数据库类型,不同数据库的限制记录语句有所不同
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        
        return interceptor;
    }
}

使用selectPage()方法实现分页功能 在这里插入图片描述

    @Test
    public void pageSelect() {
        // 从第2页开始,每页显示2条,条件为null,需要注意Page.of是新版本才有的功能,3.4.0版本没有
        IPage<User> userIPage = userMapper.selectPage(Page.of(2, 2), null);

        // 总页数
        userIPage.getPages();

        // 总记录数
        userIPage.getTotal();

        // 当前页码
        userIPage.getCurrent();

        // 每页显示的条数
        userIPage.getSize();

        // 当前页的数据
        userIPage.getRecords();

        for (User record : userIPage.getRecords()) {
            System.out.println("record = " + record);
        }
    }

可以看到分页查询功能正常(只查询出第2页的记录)、逻辑删除功能正常(del字段为1的记录未被查询出来);

在这里插入图片描述

(7)代码生成器

代码生成指Mybatis-Plus可以根据数据表,自动生成对应的实体类、三层框架、mapper.xml文件代码;官网有提供对应的功能,但在Github上也有大神提供,我这里是用了Github用户(davidfantasy)的代码(github.com/davidfantas…

在这里插入图片描述

第一步:添加依赖

添加该代码的依赖

        <!--github上复制的代码生成器 davidfantasy -->
        <dependency>
            <groupId>com.github.davidfantasy</groupId>
            <artifactId>mybatis-plus-generator-ui</artifactId>
            <version>2.0.5</version>
        </dependency>

第二步:修改代码

修改下载下来的代码,适配自己的环境 在这里插入图片描述

第三步:运行使用

该类中是main()方法,可以直接运行使用,端口号是8068

(选择仅有的一张表,点代码生成)

在这里插入图片描述


(选择Entity,实体类)

在这里插入图片描述

(生成完成后会自动打开目录,点开目录找到生成后的实体类)

在这里插入图片描述

(可以看到查看生成后的实体类内容)

在这里插入图片描述

总结

MyBatis-Plus是一款非常强大的框架,提供了一系列对数据库操作的API和技术,让开发人员免于编写大量繁琐的SQL语句,关注于业务逻辑的开发。

首次发布

hezhongying.blog.csdn.net/article/det…