MyBatis-Plus 学习笔记

本文是一份详细的MyBatis-Plus学习笔记,涵盖快速入门、常用注解、CRUD接口、条件构造器、分页功能、乐观锁插件以及扩展功能,如代码生成器和自动填充。通过实例解析MyBatis-Plus的使用方法,包括Entity、Mapper和服务层的配置和操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MyBatis-Plus 学习笔记

学习官网: https://mp.baomidou.com/guide/

一、快速入门

1.简介

  • MyBatis的增强工具,在Mybatis的基础上只做增强功能,兼容MyBatis

image-20210408161340520

我们的愿景是成为 MyBatis 最好的搭档,就像 魂斗罗 中的 1P、2P,基友搭配,效率翻倍。

image-20210408155301995

2.快速开始

2.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');

表:

image-20210408160921022

2.2 创建spring boot项目

image-20210408160115147

2.3 引入依赖

除了创建项目引入的那些常用的依赖外,还需要引入mybatis-plus和mysql驱动的依赖

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>
2.4 配置

yml配置

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/bookstore
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: '073838'
2.5 编写bean和mapper

User:

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

UserMapper:

@Mapper//也可以在springboot主类上标@MapperScan注解
public interface UserMapper extends BaseMapper<User> {

}
2.6 开始使用

使用测试类进行测试:

@SpringBootTest
class MpApplicationTests {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void testSelect() {
        System.out.println(("----- selectAll method test ------"));
        List<User> userList = userMapper.selectList(null);
        for (User user: userList){
            System.out.println(user);
        }
    }

}

运行结果:

image-20210408162801578

3.常用注解

@TableName

描述:表名注解,标在实体类中

常用属性:

  • value:表名
  • schema:对应的schema
  • resultMap:sql映射文件中 resultMap 的 id

使用:

@Data
@TableName(value = "user", schema = "bookstore", resultMap = "book")
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

注意:resultMap 若使用,需要编写相应的sql映射文件来映射,否则会报错

@TableId

描述:主键注解

属性:

image-20210408164411014

IdType:设置自动生成主键值的策略

image-20210408164433418

@TableField

描述:字段注解(非主键)

属性:详见https://mp.baomidou.com/guide/annotation.html#tablefield

  • value:数据库字段名
  • el:映射为原生 #{ ... } 逻辑,相当于写在 xml 里的 #{ ... } 部分
  • exist:是否为数据库表字段。若为false,该属性不会映射到数据库表的字段

示例:

@TableName(value = "user", schema = "bookstore")
public class User {
    @TableId(value = "id")
    private Long id;
    @TableField(exist = true, value = "email")
    private String name;
    private Integer age;
    private String email;
}

运行结果:

image-20210408165237695

@Version注解

描述:乐观锁注解、标记,标记@Version在字段上

@EnumValue
  • 描述:通枚举类注解(注解在枚举字段上)

二、CRUD接口

1.Service CRUD接口

IService提供了给service层进行CRUD的接口,需要配合Mapper层的接口一起使用。主要有save、remove、update、getOne、list等。示例:

@SpringBootTest
public class CRUDTest {
    @Autowired
    UserService userService;

    @Test
    public void saveTest(){
        User user = new User();
        user.setAge(18);
        user.setEmail("aaaa@126.com");
        user.setName("anpu");
        List<User> list = new ArrayList<>();
        for(int i = 0; i < 15; i++){
            list.add(user);
        }
        userService.save(user);
        userService.saveBatch(list);
    }

    @Test
    public void getTest(){
        User user = userService.getById("1");
        List<User> users = userService.list();
        System.out.println("one:" + user);
        System.out.println("--------------------");
        users.forEach(System.out::println);
    }

    @Test
    public void updateTest(){
        User user = userService.getById(6);
        user.setAge(3);
        user.setName("deserts");
        userService.updateById(user);
    }

    @Test
    public void deleteTest(){
        userService.removeById(6);
        Map<String, Object> map = new HashMap<>();
        map.put("name", "anpu");
        userService.removeByMap(map);
    }

    @Test
    public void saveOrUpdateTest(){
        User user = userService.getById(3);
        user.setName("lala");
        user.setId(6L);
        userService.saveOrUpdate(user);
    }

    @Test
    public void countTest(){
        System.out.println(userService.count());
    }

}

2.Mapper CRUD层接口

BaseMapper提供了Mapper层进行CRUD的接口。主要有delete、select、update、Insert接口。

3.两层CRUD接口的使用

1.Mapper层接口继承BaseMapper接口

@Mapper
public interface UserMapper extends BaseMapper<User> {

}

2.Service层创建接口去继承IService接口

public  interface UserService extends IService<User> {
}

3.创建service实现类去继承ServiceImpl,实现service接口,妻子ServiceImpl是Iservice的实现类,避免重写很多方法

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

}

三、条件构造器

说明:

QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父类
用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件
注意: entity 生成的 where 条件与 使用各个 api 生成的 where 条件没有任何关联行为

AbstractWrapper

AbstractWrapper是抽象类,封装了基本的条件方法,提供给QueryWrapper和UpdateWrapper继承使用。

提供的条件方法:
  • allEq, eq, ne:等于(map),等于(单个),不等于
  • gt,ge,lt,le: 大于,大于等于,小于,小于等于
  • between,notBetween: 在A和B之间,不在A和B之间
  • like: 模糊查询。示例: like(“name”, “王”)--->name like ‘%王%’
  • notLike: 模糊查询。示例: notLike(“name”, “王”)--->name not like ‘%王%’
  • likeLeft: 模糊查询。示例:likeLeft(“name”, “王”)--->name like ‘%王’
  • likeRight: 模糊查询。示例:likeRight(“name”, “王”)--->name like ‘王%’
  • isNull, isNotNUll: 是否为空
  • in,notIn: 取值范围
  • inSql, notInSql: 子查询。示例:inSql(“id”, “select id from table where id < 3”)--->id in (select id from table where id < 3)
  • groupBy: 分组查询。示例: groupBy(“id”, “name”)--->group by id,name
  • orederByAsc,orederByDsc,orederBy: 按字段升降序排序查找
  • having: 示例:having(“sum(age) > 10”)--->having sum(age) > 10
  • or,and: 条件嵌套。示例:eq(“id”,1).or().eq(“name”,“老王”)--->id = 1 or name = ‘老王’
  • exists,notExists: 子查询。示例:exists(“select id from table where age = 1”)--->exists (select id from table where age = 1)
conditonal参数

如:notExists(boolean condition, String notExistsSql);默认为true,若为false,表示该条件失效。

QueryWrapper

QueryWrapper继承AbstractWrapper。除了AbstractWrapper外,还有select()用于设置查询字段:

select(String... sqlSelect)
select(Predicate<TableFieldInfo> predicate)
select(Class<T> entityClass, Predicate<TableFieldInfo> predicate)

说明:

以上方法分为两类.
第二类方法为:过滤查询字段(主键除外),入参不包含 class 的调用前需要wrapper内的entity属性有值! 这两类方法重复调用以最后一次为准

  • 例: select("id", "name", "age")
  • 例: select(i -> i.getProperty().startsWith("test"))

UpdateWrapper

说明:

继承自 AbstractWrapper ,自身的内部属性 entity 也用于生成 where 条件
LambdaUpdateWrapper, 可以通过 new UpdateWrapper().lambda() 方法获取!

set

为某个字段的所以值设置为一个值,如set(“name”, null)--->数据库字段值变为null

set(String column, Object val)
set(boolean condition, String column, Object val)
setSql
  • 设置 SET 部分 SQL
  • 例: setSql("name = '老李头'")

四、分页功能

1.加入分页插件

@Configuration
public class MyBatisConfiguration {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
        // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求  默认false
        paginationInnerInterceptor.setOverflow(true);
        // 设置最大单页限制数量,默认 500 条,-1 不受限制
        paginationInnerInterceptor.setMaxLimit(100L);
        mybatisPlusInterceptor.addInnerInterceptor(paginationInnerInterceptor);
        return mybatisPlusInterceptor;
    }
}

2.使用service层的接口实现分页

    @Test
    public void pageTest(){
        Page<User> page = new Page<>(1, 5);
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("name", "anpu");
        Page<User> userPage = userService.page(page, wrapper);
        List<User> records = userPage.getRecords();
        System.out.println("---------" + userPage);
        System.out.println("-------->" + userPage.getTotal());
        System.out.println("-------->" + userPage.getSize());
        records.forEach(System.out::println);
    }

控制台输出:

---------com.baomidou.mybatisplus.extension.plugins.pagination.Page@44114b9f
-------->16
-------->5
User(id=15, name=anpu, age=18, email=aaaa@126.com)
User(id=16, name=anpu, age=18, email=aaaa@126.com)
User(id=17, name=anpu, age=18, email=aaaa@126.com)
User(id=18, name=anpu, age=18, email=aaaa@126.com)
User(id=19, name=anpu, age=18, email=aaaa@126.com)

五、乐观锁插件

MybatisPlusInterceptor

该插件是核心插件,目前代理了 Executor#queryExecutor#updateStatementHandler#prepare 方法

目前已有的功能:

  • 自动分页: PaginationInnerInterceptor
  • 多租户: TenantLineInnerInterceptor
  • 动态表名: DynamicTableNameInnerInterceptor
  • 乐观锁: OptimisticLockerInnerInterceptor
  • sql性能规范: IllegalSQLInnerInterceptor
  • 防止全表更新与删除: BlockAttackInnerInterceptor

使用顺序:

使用多个功能需要注意顺序关系,建议使用如下顺序

  • 多租户,动态表名
  • 分页,乐观锁
  • sql性能规范,防止全表更新与删除

总结: 对sql进行单次改造的优先放入,不对sql进行改造的最后放入

乐观锁实现

什么是乐观锁?当要更新一条记录的时候,希望这条记录没有被别人更新

乐观锁的实现方式:

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

使用方法:

1.数据库表添加字段version

2.实体类使用@version标注

@Data
@TableName(value = "user", schema = "bookstore")
public class User {
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
    @Version
    private Long version;
}

  • 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
  • 整数类型下 newVersion = oldVersion + 1
  • newVersion 会回写到 entity
  • 仅支持 updateById(id)update(entity, wrapper) 方法
  • update(entity, wrapper) 方法下, wrapper 不能复用!!!

3.配置类加入乐观锁插件,乐观锁生效

@Configuration
public class MyBatisConfiguration {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        //分页插件
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
        // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求  默认false
        paginationInnerInterceptor.setOverflow(true);
        // 设置最大单页限制数量,默认 500 条,-1 不受限制
        paginationInnerInterceptor.setMaxLimit(100L);
        //乐观锁插件
        OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor = new OptimisticLockerInnerInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(paginationInnerInterceptor);
        mybatisPlusInterceptor.addInnerInterceptor(optimisticLockerInnerInterceptor);
        return mybatisPlusInterceptor;
    }
}

六、扩展功能

1.代码生成器

添加依赖:MyBatis-Plus 从 3.0.3 之后移除了代码生成器与模板引擎的默认依赖,需要手动添加相关依赖:

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.3</version>
        </dependency>

编写代码:

 @Test
    public void test(){
        //创建代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setEntityName("bean");
        gc.setMapperName("mapper");
        gc.setServiceName("service");
        gc.setControllerName("controller");
        //是否覆盖之前的文件
        gc.setFileOverride(true);
        gc.setAuthor("deserts");
        gc.setOpen(false);
        //实体属性 Swagger2 注解
        gc.setSwagger2(true);
        mpg.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/bookstore?useUnicode=true&useSSL=false&characterEncoding=utf8");
        dsc.setDriverName("com.mysql.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("073838");
        mpg.setDataSource(dsc);

        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("auto");
        pc.setParent("com.deserts");
        mpg.setPackageInfo(pc);


        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);
        //包含的表名
        strategy.setInclude("user");
        //设置逻辑删除字段
        strategy.setLogicDeleteFieldName("deleted");
        //设置自动填充字段
        TableFill gmt_create = new TableFill("gmt_create", FieldFill.INSERT);
        TableFill gmt_update = new TableFill("gmt_update", FieldFill.INSERT_UPDATE);
        strategy.setTableFillList(Arrays.asList(gmt_create, gmt_update));
        //设置乐观锁version字段
        strategy.setVersionFieldName("version");
        mpg.setStrategy(strategy);

        //执行
        mpg.execute();
    }

2.逻辑删除

1.数据库表中增加一个逻辑删除的字段:

image-20210410125742251

2.配置yml

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: flag  # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

3.实体类中指定逻辑删除字段:

@TableLogic
private Integer deleted;

4.测试

    @Test
    public void deletedTest(){
        userService.removeById(1);
    }

5.实际执行的语句

UPDATE bookstore.user SET deleted=1 WHERE id=? AND deleted=0

6.加上逻辑删除后执行查找:

    @Test
    public void select(){
        User user = userService.getById(1);
        System.out.println(user);
    }

此时执行的sql:

SELECT id,name,age,email,version,deleted FROM bookstore.user WHERE id=? AND deleted=0

3.自动填充功能

实现数据库表的更新有记录:gmt_create,gmt_modified

方式一:基于数据库表

创建时间不需要勾选根据时间戳更新:

image-20210410132227885

效果:

image-20210410132301212

执行更新操作后:

image-20210410132411259

方式二:代码中设置

表中创建两个字段:

image-20210410132719446

实体类注解填充字段:

    @TableField(fill = FieldFill.INSERT)
    private Date cmtCreate;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date cmtModified;

自定义实现类MyMetaObjectHandler:

@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill ....");
        this.setFieldValByName("cmtCreate", new Date(), metaObject);
        this.setFieldValByName("cmtModified", new Date(), metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill ....");
        this.setFieldValByName("cmtModified", new Date(), metaObject);
    }
}

更新操作后:

image-20210410134926461

4.日志分析

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值