一文MyBatis-Plus快速入门

2,161 阅读6分钟

一、依赖及配置

使用下面的SQL创建数据库与添加数据

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、在idea中创建一个SpringBoot项目,在pom.xml中添需要的依赖

添加MyBatis-Plus、mysql连接驱动、lombok的依赖

<dependency>
    <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.0.5</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>

2、配置数据库连接

application.yml

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mp
    username: root
    password: 1234

3、在启动类中添加注解 @MapperScan 扫描Mapper接口包

@SpringBootApplication
@MapperScan("com.jikedaquan.study.mp.mapper")
public class MpApplication {

    public static void main(String[] args) {
        SpringApplication.run(MpApplication.class, args);
    }

}

4、编写实体类,使用lombok

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

5、编写UserMapper接口

UserMapper接口继承MyBatis-Plus提供的BaseMapper接口即可拥有CRUD的方法,泛型中填写操作的实体类,这里为User

public interface UserMapper extends BaseMapper<User> {
}

6、测试查询数据

@RunWith(SpringRunner.class)
@SpringBootTest
public class MpApplicationTests {
    @Autowired
    private UserMapper userMapper;
    @Test
    public void contextLoads() {
        List<User> userList = userMapper.selectList(null);//条件为null时查询所有数据
        userList.forEach(System.out::println);
    }
}

二、日志配置

配置日志到控制台输出

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

三、主键生成策略

MyBatis-Plus提供了多种主键生成策略以应对不同的场景

策略 说明
AUTO 数据库ID自增
NONE 该类型为未设置主键类型
INPUT 用户输入ID,该类型可以通过自己注册自动填充插件进行填充
ID_WORKER 全局唯一ID (idWorker)
UUID 全局唯一ID (UUID)
ID_WORKER_STR 字符串全局唯一ID (idWorker 的字符串表示)

1、注解控制主键生成策略

在实体类的主键字段上添加注解(自增时注意配合数据库设置)

@Data
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

2、全局配置控制主键生成策略

application.yml

mybatis-plus:
  global-config:
    db-config:
      id-type: id_worker

四、自动填充

在常用业务中有些属性需要配置一些默认值,MyBatis-Plus提供了实现此功能的插件。在这里修改user表添加 create_time 字段和 update_time 字段,在User类中添加对应属性。

1、为需要自动填充的属性添加注解 @TableField

提供了4种自动填充策略:DEFAULT,默认不处理。INSERT,插入填充字段。UPDATE,更新填充字段。INSERT_UPDATE,插入和更新填充字段。

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

    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
}

2、实现字段填充控制器,编写自定义填充规则

实现 MetaObjectHandler 接口,实现 insertFill 和 updateFill 方法,此处的 create_timeupdate_time字段需要插入时填充值, 只有 update_time 字段在修改时需要填充,所以策略如下。

//需要将自定义填充控制器注册为组件
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    private static final Logger LOGGER= LoggerFactory.getLogger(MyMetaObjectHandler.class);

    //insert操作时要填充的字段
    @Override
    public void insertFill(MetaObject metaObject) {
        LOGGER.info("start insert fill ...");
        //根据属性名字设置要填充的值
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }

    //update操作时要填充的字段
    @Override
    public void updateFill(MetaObject metaObject) {
        LOGGER.info("start insert fill ...");
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
}

3、插入数据测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class CRUDTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testInsert(){
        User user = new User();
        user.setName("jack11");
        user.setAge(20);
        user.setEmail("4849111@qq.com");

        int result= userMapper.insert(user);
        System.out.println(result);
        System.out.println(user);
    } 
}

4、修改数据测试

@Test
public void testUpdate(){
    User user = new User();
    user.setId(2L);
    user.setName("Jackie");
    int result = userMapper.updateById(user);
    System.out.println(result);
}

一次插入数据后,create_timeupdate_time都被填充了设置的时间,做update操作后只有update_time的进行了填充修改。

五、乐观锁插件

乐观锁的核心原理就是提交版本必须等于记录当前版本才能执行更新

意图:

  • 当要更新一条记录的时候,希望这条记录没有被别人更新

乐观锁实现方式:

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败

1、添加version到表和类中,为属性添加 @Version 注解

@Version
private Integer version;

2、配置插件

@Configuration
public class MyBatisPlusConfig {

    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor(){
        return new OptimisticLockerInterceptor();
    }
}

3、测试修改的两种情况

@Test
public void testOptimisticLocker1() {
    User user = userMapper.selectById(1128212430124097543L);
    user.setName("修改后");
    int result = userMapper.updateById(user);
    if (result == 1) {
        System.out.println("修改成功");
    } else {
        System.out.println("修改失败");
    }
}

@Test
public void testOptimisticLocker2() {
    User user = userMapper.selectById(1128212430124097543L);
    user.setName("修改后");
    user.setVersion(user.getVersion()-1);//测试旧版本
    int result = userMapper.updateById(user);
    if (result == 1) {
        System.out.println("修改成功");
    } else {
        System.out.println("修改失败");
    }
}

六、分页插件

启用分页插件和启用乐观锁插件都是通过注册一个Bean完成

1、启用分页插件

@Bean
public PaginationInterceptor paginationInterceptor(){
    return new PaginationInterceptor();
}

2、测试分页查询

@Test
public void testSelectPage(){
    //构建分页条件第二页每页显示3条
    Page<User> page=new Page<>(2,3);
    //使用分页条件查询,不使用其他条件
    userMapper.selectPage(page, null);
    //获取分页后查询出的记录
    List<User> records = page.getRecords();
    records.forEach(System.out::println);
    System.out.println("是否有下一页:"+page.hasNext());
    System.out.println("是否有上一页:"+page.hasPrevious());
    System.out.println("总记录数:"+page.getTotal());
}

七、逻辑删除插件

有些数据希望不再展示,但在物理上仍然存在,这时可以使用逻辑删除。逻辑删除就是在表中添加一个逻辑字段(在上面基础上添加字段 deleted),删除的实质操作就是操作这个逻辑值,在查询、修改时根据此逻辑值进行近一步操作。

1、启用逻辑删除插件

@Bean
public LogicSqlInjector logicSqlInjector(){
    return new LogicSqlInjector();
}

2、添加逻辑映射配置

mybatis-plus:
  global-config:
    db-config:
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

3、逻辑字段添加注解 @TableLogic

@TableLogic
private Integer deleted;

4、测试逻辑删除

@Test
public void testLogicDelete(){
    int result=userMapper.deleteById(1L);
    System.out.println(result);
}

观察日志可以看到生成的sql是update语句

八、性能分析插件

在开发和测试时观察sql执行耗时

1、配置SpringBoot为开发环境

spring:
  profiles:
    active: dev

2、启用插件

@Bean
@Profile({"dev","test"}) //设置 dev test 环境开启
public PerformanceInterceptor performanceInterceptor(){
    return new PerformanceInterceptor();
}

九、CRUD其他操作

@Test
public void testSelectById() {
    User user = userMapper.selectById(1L);
    System.out.println(user);
}

@Test
public void testSelectBatchIds() {
    List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
    users.forEach(System.out::println);
}

@Test
public void testSelectByMap() {
    Map<String, Object> param = new HashMap<>();
    param.put("name", "jack");
    param.put("age", 18);
    List<User> users = userMapper.selectByMap(param);
    users.forEach(System.out::println);
}

@Test
public void testSelectMap(){
    Page<User> page = new Page<>(2, 3);
    IPage<Map<String, Object>> mapIPage = userMapper.selectMapsPage(page, null);
}

@Test
public void testDeleteById(){
    int result = userMapper.deleteById(1L);
    System.out.println(result);
}

@Test
public void testDeleteBatchIds(){
    int result = userMapper.deleteBatchIds(Arrays.asList(2L,3L,4L));
    System.out.println(result);
}

欢迎热爱技术的小伙伴和我交流