Mybatis-Plus使用与配置

2020-08-25  本文已影响0人  攻城老狮

本测试项目涵盖了Mybatis-Plus框架的入门快速构建以及基本的CRUD相关的操作说明。望可以帮助到有相关需求的伙伴。
测试代码Github地址:https://github.com/yaokuku123/mybatis-demo

1 Mybatis-Plus快速搭建

本项目测试需要基于SpringBoot框架完成。

1.1 创建并初始化数据库

DROP TABLE IF EXISTS user;

CREATE TABLE user
(
    id BIGINT(20) NOT NULL COMMENT '主键ID',
    name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
    age INT(11) NULL DEFAULT NULL COMMENT '年龄',
    email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
    PRIMARY KEY (id)
);
DELETE FROM user;

INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');

1.2 初始化Maven工程,并引入依赖

注意:引入 MyBatis-Plus 无需再引入 MyBatis 以及 MyBatis-Spring,以避免因版本差异导致的问题。

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <!--mybatis-plus-->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.0.5</version>
    </dependency>
    <!--mysql驱动-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!--lombok-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
    </dependency>
</dependencies>

1.3 主配置类中的配置

#mysql数据库连接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456

#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

1.4 编写代码

注意:在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹。

package com.yqj;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.yqj.mapper")
public class MybatisPlusApplication {
    public static void main(String[] args) {
        SpringApplication.run(MybatisPlusApplication.class,args);
    }
}

package com.yqj.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

注意:让UserMapper接口继承mybatisplus中的BaseMapper<User>接口

package com.yqj.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yqj.entity.User;

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

1.5 测试

package com.yqj;

import com.yqj.entity.User;
import com.yqj.mapper.UserMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void testSelectList(){
        List<User> users = userMapper.selectList(null);
        for (User user : users) {
            System.out.println(user);
        }
    }
}

输出:说明成功实现基于Mybatis-Plus的快速入门操作

User(id=1, name=Jone, age=18, email=test1@baomidou.com)
User(id=2, name=Jack, age=20, email=test2@baomidou.com)
User(id=3, name=Tom, age=28, email=test3@baomidou.com)
User(id=4, name=Sandy, age=21, email=test4@baomidou.com)
User(id=5, name=Billie, age=24, email=test5@baomidou.com)

2. Mybatis-Plus的CRUD相关操作

基于之前搭建的快速搭建的程序测试CRUD的相关操作

2.1 insert

注意:数据库插入id值默认为:ID_WORKER 全局唯一id

//插入用户数据
@Test
public void testInsert(){
    User user = new User();
    user.setName("yorick");
    user.setAge(18);
    user.setEmail("yorick@qq.com");
    int result = userMapper.insert(user);
    System.out.println(result);
}
1.IdType.AUTO 主键自增策略
2.IdType.ID_WORKER 若主键为数值型,Mybatis-Plus默认使用的策略
3.IdType.ID_WORKER_STR 若主键为字符串型,Mybatis-Plus默认使用的策略
4.IdType.INPUT 主键id需要手动输入
5.IdType.NONE 默认跟随全局策略
6.IdType.UUID 生成UUID

在实体类的主键上增加主键生成策略的字段注解即可

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

2.2 update

//更新用户数据
@Test
public void testUpdate(){
    User user = userMapper.selectById(1L);
    user.setName("alice");
    int result = userMapper.updateById(user);
    System.out.println(result);
}

项目中经常会遇到一些数据,每次都使用相同的方式填充,例如记录的创建时间,更新时间等。我们可以使用MyBatis Plus的自动填充功能,完成这些字段的赋值工作。

测试:

  1. 在数据库中添加两个datetime类型的新字段 create_time、update_time
ALTER TABLE `user` ADD COLUMN `create_time` datetime
ALTER TABLE `user` ADD COLUMN `update_time` datetime
  1. 在对应实体类的属性上添加注解
//在插入时自动填充
@TableField(fill = FieldFill.INSERT)
private Date createTime;
//在插入和更新时自动填充
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
  1. 实现元对象处理器接口
package com.yqj.handler;

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

import java.util.Date;

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    //设置执行插入时,自动填充的内容
    @Override
    public void insertFill(MetaObject metaObject) {
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }

    //设置执行更新时,自动填充的内容
    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
}

  1. 测试
//插入用户数据
@Test
public void testInsert(){
    User user = new User();
    user.setName("yorick2");
    user.setAge(19);
    user.setEmail("yorick2@qq.com");
    int result = userMapper.insert(user);
    System.out.println(result);
}

当要更新一条记录的时候,希望这条记录没有被别人更新,也就是说实现线程安全的数据更新。

乐观锁实现方式:

测试:

  1. 数据库添加version字段
ALTER TABLE `user` ADD COLUMN `version` INT
  1. 实体类的对应属性上添加注解
@Version
@TableField(fill = FieldFill.INSERT) //设置插入时自动填充
private Integer version;
  1. 元对象处理器接口添加version的insert默认值
@Override
public void insertFill(MetaObject metaObject) {
    ......
    this.setFieldValByName("version", 1, metaObject);
}
  1. 注册乐观锁的配置插件

另外,将原来标注在主启动类上的 @MapperScan 注解转移到配置类上面

package com.yqj.config;

import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("com.yqj.mapper")
public class MybatisPlusConfig {
    
    //乐观锁插件
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor(){
        return new OptimisticLockerInterceptor();
    }
}

  1. 测试

将id为1的记录中version字段改为1,然后执行测试发现结果为2,说明乐观锁配置成功。

//更新用户数据
@Test
public void testUpdate(){
    User user = userMapper.selectById(1L);
    user.setName("alice2");
    int result = userMapper.updateById(user);
    System.out.println(result);
}

2.3 select

//根据id查询
@Test
public void testSelectById(){
    User user = userMapper.selectById(1L);
    System.out.println(user);
}
//多个id批量查询
@Test
public void testSelectBatchIds(){
    List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 3L));
    for (User user : users) {
        System.out.println(user);
    }
}

注意:map中的key对应的是数据库中的列名。例如数据库user_id,实体类是userId,这时map的key需要填写user_id

//map封装的条件查询
@Test
public void testSelctByMap(){
    Map<String,Object> map = new HashMap<>();
    map.put("name","yorick");
    map.put("age",18);
    List<User> users = userMapper.selectByMap(map);
    for (User user : users) {
        System.out.println(user);
    }
}

最终通过page对象获取相关数据

测试:

  1. 在配置类中添加分页插件
//分页插件
@Bean
public PaginationInterceptor paginationInterceptor(){
    return new PaginationInterceptor();
}
  1. 测试selectPage分页
//分页查询
@Test
public void testSelectPage(){
    Page<User> page = new Page<>(1, 3); 
    userMapper.selectPage(page, null);
    page.getRecords().forEach(System.out::println); //当前页的数据
    System.out.println(page.getCurrent()); //当前页
    System.out.println(page.getPages()); //总页数
    System.out.println(page.getSize()); //每页显示的数据条目
    System.out.println(page.getTotal()); //总共的数据条目
    System.out.println(page.hasNext()); //是否有下一页
    System.out.println(page.hasPrevious()); //是否有上一页
}

2.4 delete

物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除数据

逻辑删除:假删除,将对应数据中代表是否被删除字段状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录

//根据id删除
@Test
public void testDeleteById(){
    int result = userMapper.deleteById(5L);
    System.out.println(result);
}

测试:

  1. 数据库中添加 deleted字段,用于表示逻辑删除
ALTER TABLE `user` ADD COLUMN `deleted` boolean
  1. 实体类的对应属性上面添加逻辑删除的注解
@TableLogic
@TableField(fill = FieldFill.INSERT) //插入时自动填充
private Integer deleted;
  1. 元对象处理器接口添加deleted的insert默认值
@Override
public void insertFill(MetaObject metaObject) {
    ......
    this.setFieldValByName("deleted", 0, metaObject);
}
  1. 在配置类中注册逻辑删除的插件
//逻辑删除
@Bean
public ISqlInjector iSqlInjector(){
    return new LogicSqlInjector();
}
  1. 测试逻辑删除

将id为4的记录中deleted字段改为0,然后执行测试发现其变为1,说明逻辑删除成功。

//根据id删除
@Test
public void testDeleteById(){
    int result = userMapper.deleteById(4L);
    System.out.println(result);
}

2.5 性能分析

性能分析拦截器,用于输出每条 SQL 语句及其执行时间

SQL 性能执行分析,开发环境使用,超过指定时间,停止运行。有助于发现问题

测试:

  1. 在配置类中添加性能分析的插件
//性能分析
@Bean
@Profile({"dev","test"})// 设置 dev test 环境开启
public PerformanceInterceptor performanceInterceptor() {
    //参数:maxTime: SQL 执行最大时长,超过自动停止运行,有助于发现问题
    //参数:format: SQL是否格式化,默认false
    PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
    performanceInterceptor.setMaxTime(500);//ms,超过此处设置的ms则sql不执行
    performanceInterceptor.setFormat(true);
    return performanceInterceptor;
}
  1. SpringBoot中设置为dev开发环境
#环境设置:dev、test、prod
spring.profiles.active=dev
  1. 测试
//插入用户数据
@Test
public void testInsert(){
    User user = new User();
    user.setName("yorick");
    user.setAge(20);
    user.setEmail("yorick@qq.com");
    int result = userMapper.insert(user);
    System.out.println(result);
}

结果:显示出插入的性能为4ms

Time:4 ms - ID:com.yqj.mapper.UserMapper.insert
Execute SQL:
    INSERT 
    INTO
        user
        ( id, name, age, email, create_time, update_time, version, deleted ) 
    VALUES
        ( 1298135534432567298, 'yorick', 20, 'yorick@qq.com', '2020-08-25 13:50:04', '2020-08-25 13:50:04', 1, 0 )

2.6 复杂查询

//复杂查询
@Test
public void testComplexSelect(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();

    //ge,gt,le,lt,isNull,isNotNull
    //查询年龄不小于20岁的用户
    //wrapper.ge("age",20);

    //eq,ne
    //查询姓名为yorick的用户
    //wrapper.eq("name","yorick");

    //between,notBetween
    //查询年龄在20~30之间的用户,包含20和30边界
    //wrapper.between("age",20,30);

    //like
    //查询姓名包含yorick的用户
    //wrapper.like("name","yorick");

    //orderByDesc,orderByAsc
    //按id降序排序
    //wrapper.orderByDesc("id");

    //last 直接拼接sql到最后,有sql注入风险
    //wrapper.last("limit 1");

    //指定要查找的列
    wrapper.select("id","name");


    List<User> users = userMapper.selectList(wrapper);
    for (User user : users) {
        System.out.println(user);
    }
}
上一篇下一篇

猜你喜欢

热点阅读