栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

MybatisPlus学习笔记

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

MybatisPlus学习笔记

目录

一、简介二、快速入门三、配置日志四、CRUD和扩展

1.insert2.update3.乐观锁插件4.select5.分页查询6.delete7.逻辑删除8.执行SQL分析打印 五、自动填充字段六、条件构造器七、代码自动生成器


提示:当前使用的版本为mybatis-plus3.5.1

一、简介

MyBatis-Plus(简称 MP)是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。简化CRUD操作。

二、快速入门

使用第三方组件步骤:

    导入对应依赖研究依赖如何配置代码如何编写提高扩展技术能力

步骤基于 spring boot项目

    创建数据库和表

    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)
    );
    # 添加数据
    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');
    

    在spring boot工程中导入Maven依赖

    
    	com.baomidou
        mybatis-plus-boot-starter
        3.5.1
    
    

    连接数据库

    spring:
        datasource:
          # mysql 8 驱动不同com.mysql.cj.jdbc.Driver 需要增加时区的配置 serverTimezone=GMT%2B8
          driver-class-name: com.mysql.jdbc.Driver
          url: jdbc:mysql://localhost:3306/database?useSSL=false&useUnicode=true&characterEncoding=utf-8
          username: root
          password: admin
    

    创建实体类User.java(必须与表名保持一致)

    @Data
    @Builder(toBuilder = true)
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
    	private Long id;
        private String name;
        private Integer age;
        private String email;
    }
    

    创建UserMapper接口并继承通用Mapper(baseMapper)泛型为User型

    public interface UserMapper extends baseMapper {
    }
    

    在springboot启动类上添加@MapperScan注解

    @SpringBootApplication
    @MapperScan("com.example.mybatisplus.mapper") //mapper接口所在的包路径
    public class MybatisPlusApplication {
    	public static void main(String[] args) {
    		SpringApplication.run(MybatisPlusApplication.class, args);
    	}
    }
    

    测试

    @SpringBootTest
    class MybatisPlusApplicationTests {
    	@Autowired
        private UserMapper userMapper;
        @Test
        void contextLoads() {
            //查询全部数据 参数为wrapper条件构造器 暂且为null
            List users = userMapper.selectList(null);
            for (User user : users) {
                System.out.println(user);
            }
        }
    }
    

    运行输出

    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)
    
三、配置日志

配置日志便于查看执行的sql语句

在spring boot配置文件中配置日志实现

# 第一种方式
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 第二种方式
logging:
  level:
  # 指定mapper接口所在的包
    com.example.mybatisplus.mapper: debug

测试输出结果

第一种方式
JDBC Connection [HikariProxyConnection@1079733621 wrapping com.mysql.cj.jdbc.ConnectionImpl@682abca7] will not be managed by Spring
==>  Preparing: SELECT id,name,age,email FROM user //执行的SQL
==> Parameters: //SQL的参数
//查询的结果
<==    Columns: id, name, age, email
<==        Row: 1, Jone, 18, test1@baomidou.com
<==        Row: 2, Jack, 20, test2@baomidou.com
<==        Row: 3, Tom, 28, test3@baomidou.com
<==        Row: 4, Sandy, 21, test4@baomidou.com
<==        Row: 5, Billie, 24, test5@baomidou.com
<==      Total: 5
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@66f28a1f]
第二种方式
==>  Preparing: SELECt id,name,age,email FROM user
==> Parameters: 
<==      Total: 5
四、CRUD和扩展 1.insert

测试单表插入

@Test
public void testInsert() {
    User user = User.builder()
        .name("zhangsan")
        .age(22)
        .email("123@qwe").build();

    //受影响行数
    int result = userMapper.insert(user);
    System.out.println(result);
    //发现id会自动填充
    System.out.println(user);

    List users = userMapper.selectList(null);
    for (User u : users) {
        System.out.println(u);
    }
}

运行结果

==> Preparing: INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )
==> Parameters: 106717185(Integer), zhangsan(String), 22(Integer), 123@qwe(String)
<==    Updates: 1
1
User(id=106717185, name=zhangsan, age=22, email=123@qwe)
...

这里MP使用了雪花算法,参考:
雪花算法(snowflake):snowflake算法是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。具体实现的代码可以参看https://github.com/twitter/snowflake。雪花算法支持的TPS可以达到419万左右(2^22*1000)。可以几乎保证全球唯一。
分布式系统唯一ID生成:分布式系统唯一ID生成方案汇总

主键自增策略,默认是IdType.NONE

配置主键自增

    在实体类主键属性上添加@TableId(type=IdType.AUTO)注解

    public class User {
    	@TableId(type = IdType.AUTO)
    	private Integer id;
    }
    

    把数据表注解字段设置为自增(auto_increment)

    测试插入运行结果

    User(id=106717186, name=zhangsan, age=22, email=123@qwe)
    

    IdType枚举属性

    public enum IdType {
    	AUTO(0),	//ID自增
        NONE(1),	//不设置主键自增
        INPUT(2),	//手动输入
        ASSIGN_ID(3),
        ASSIGN_UUID(4);
    }
    
2.update

单表更新

@Test
public void testUpdate(){
    User user = User.builder()
        .id(106717186)
        .name("lisi123")
        //.age(23)
        .email("321@qwe").build();
    //更新操作会自动拼接sql
    int result = userMapper.updateById(user);
    System.out.println(result);
}

运行结果

==>  Preparing: UPDATE user SET name=?, email=? WHERe id=?
==> Parameters: lisi123(String), 321@qwe(String), 106717186(Integer)
<==    Updates: 1
1
3.乐观锁插件

乐观锁:顾名思义十分乐观,它总是认为不会出现问题,无论干什么都不会上锁!如果出现问题就再次更新值测试。
悲观锁:顾名思义十分乐观,它总是认为会出现问题,无论干什么都会上锁!再去操作。

乐观锁实现方式:

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

测试MP的乐观锁插件

    在数据表中添加version字段
    同步实体类
    public class User {
    	@TableId(type = IdType.AUTO)
        private Integer id;
        private String name;
        private Integer age;
        private String email;
        @Version	//乐观锁Version注解
        private Integer version;
        @TableField(fill = FieldFill.INSERT)
        private Date createDate;
        @TableField(fill = FieldFill.INSERT_UPDATE)
        private Date modifyDate;
    }
    
    注册组件,创建MP配置类,向MybatisPlusInterceptor拦截器中添加OptimisticLockerInnerInterceptor拦截器
    @Configuration
    @MapperScan("com.example.mybatisplus.mapper")
    public class MybatisPlusConfig {
    	@Bean
        public MybatisPlusInterceptor mybatisPlusInterceptor() {
            MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
            interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
            return interceptor;
        }
    }
    
    测试乐观锁
    @Test
    public void testOptimismLock(){
    	//模拟线程A
        User user1 = userMapper.selectById(1);
        user1.setAge(22);
        //模拟线程B 执行了插队操作
        User user2 = userMapper.selectById(1);
        user2.setAge(18);
        //线程B抢先更新
        userMapper.updateById(user2);
        //由于线程B已经更新完成了,线程A更新失败
        userMapper.updateById(user1);
    }
    
    运行结果
    ==>  Preparing: SELECT id,name,age,email,version,create_date,modify_date FROM user WHERe id=?
    ==> Parameters: 1(Integer)
    <==    Columns: id, name, age, email, version, create_date, modify_date
    <==        Row: 1, Jone, 18, test1@baomidou.com, 1, 2022-02-07 17:39:39, 2022-02-07 17:39:40
    <==      Total: 1
    
    ==>  Preparing: SELECt id,name,age,email,version,create_date,modify_date FROM user WHERe id=?
    ==> Parameters: 1(Integer)
    <==    Columns: id, name, age, email, version, create_date, modify_date
    <==        Row: 1, Jone, 18, test1@baomidou.com, 1, 2022-02-07 17:39:39, 2022-02-07 17:39:40
    <==      Total: 1
    
    ==>  Preparing: UPDATe user SET name=?, age=?, email=?, version=?, create_date=?, modify_date=? WHERe id=? AND version=?
    ==> Parameters: Jone(String), 23(Integer), test1@baomidou.com(String), 2(Integer), 2022-02-07 17:39:39.0(Timestamp), 2022-02-07 19:21:30.42(Timestamp), 1(Integer), 1(Integer)
    <==    Updates: 1
    
    ==>  Preparing: UPDATE user SET name=?, age=?, email=?, version=?, create_date=?, modify_date=? WHERe id=? AND version=?
    ==> Parameters: Jone(String), 22(Integer), test1@baomidou.com(String), 2(Integer), 2022-02-07 17:39:39.0(Timestamp), 2022-02-07 19:21:30.441(Timestamp), 1(Integer), 1(Integer)
    <==    Updates: 0
    
4.select
@Test
public void testSelect() {
    //根据ID查询
    User user = userMapper.selectById(1);
    System.out.println(user);

    //根据多个ID查询
    List users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3, 4, 5));
    System.out.println(users.toString());

    //自定义条件查询之一使用Map操作
    Map map = new HashMap<>();
    map.put("age",18);
    map.put("name","Jone");
    List userList = userMapper.selectByMap(map);
    System.out.println(userList);
}
5.分页查询

配置步骤

    在MP配置类中配置分页插件
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
    	MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //添加乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        //添加分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return interceptor;
    }
    
    使用selectPage()测试分页
    @Test
    public void testPageSelect() {
    	//Page构造器参数(currentPage,PageSize)
        Page page = new Page<>(3, 5);
    
        userMapper.selectPage(page, null);
        //获取分页记录
        List users = page.getRecords();
        for (User user : users) {
            System.out.println(user);
        }
        //获取当前页
        System.out.println(page.getCurrent());
        //获取总页数
        System.out.println(page.getPages());
        //获取当前页记录数
        System.out.println(page.getSize());
        //获取总记录数
        System.out.println(page.getTotal());
    }
    
6.delete
@Test
public void testDelete() {
    int result = 0;
    //根据ID删除
    result = userMapper.deleteById(106717187);
    System.out.println(result);
    //根据多个ID删除
    result = userMapper.deleteBatchIds(Arrays.asList(106717188, 106717189));
    System.out.println(result);
    //自定义删除条件之一使用Map操作
    Map map = new HashMap<>();
    map.put("name","Tue Feb 08 10:25:31 CST 2022");
    result = userMapper.deleteByMap(map);
    System.out.println(result);
}
7.逻辑删除

逻辑删除:逻辑删除本质是修改,数据库中没有被删除,而是使用另一个变量(字段),让它失效
物理删除:从数据库中永久删除

作用:管理员可以查看被删除的记录,防止数据丢失,类似于回收站

实现步骤

    在数据表中添加deleted字段

    同步实体类

    @TableField(fill = FieldFill.INSERT)
    @TableLogic //添加逻辑删除注解
    private Integer deleted;
    

    在springboot配置文件中添加配置

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

    测试

    @Test
    public void testLogicDelete() {
    	//删除
        int result = userMapper.deleteById(106717193);
        System.out.println(result);
    
        //查询
        User user = userMapper.selectById(106717193);
        System.out.println(user);
    }
    

    输出日志

    //更新deleted字段值,并添加deleted=0条件
    ==>  Preparing: UPDATE user SET deleted=1 WHERe id=? AND deleted=0
    ==> Parameters: 106717193(Integer)
    <==    Updates: 1
    
    //查询语句也添加deleted=0条件
    ==>  Preparing: SELECT id,name,age,email,deleted,version,create_date,modify_date FROM user WHERe id=? AND deleted=0
    ==> Parameters: 106717193(Integer)
    <==      Total: 0
    
8.执行SQL分析打印

该功能依赖 p6spy 组件

    p6spy依赖Maven
    
    	p6spy
    	p6spy
    	最新版本
    
    
    在springboot配置文件中配置
    spring:
      datasource:
        # driver-class-name 改为com.p6spy.engine.spy.P6SpyDriver
        driver-class-name: com.p6spy.engine.spy.P6SpyDriver
        # url前缀为jdbc:p6spy:
        url: jdbc:p6spy:mysql://localhost:3306/mybatis_plus
        ...
    
    创建p6spy配置文件spy.properties
    #3.2.1以上使用
    modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
    #3.2.1以下使用或者不配置
    #modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
    # 自定义日志打印
    logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
    #日志输出到控制台
    appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
    # 使用日志系统记录 sql
    #appender=com.p6spy.engine.spy.appender.Slf4JLogger
    # 设置 p6spy driver 代理
    deregisterdrivers=true
    # 取消JDBC URL前缀
    useprefix=true
    # 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
    excludecategories=info,debug,result,commit,resultset
    # 日期格式
    dateformat=yyyy-MM-dd HH:mm:ss
    # 实际驱动可多个
    #driverlist=org.h2.Driver
    # 是否开启慢SQL记录
    outagedetection=true
    # 慢SQL记录标准 2 秒
    outagedetectioninterval=1
    
    运行测试输出结果
五、自动填充字段

例如几乎所有的数据表都要有create_date、modify_date字段,有些时候不能直接在数据表上更改

方式一:数据库级别

    在表中新增字段create_date、modify_date

    同步实体类

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

    更新测试

方式二:代码级别

    删除数据表字段的默认值

    在实体类属性上添加注解@TableField注解

    @TableField(fill = FieldFill.INSERT)
    private Date createDate;
    
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date modifyDate;
    

    创建数据填充处理器实现metaObjectHandler接口

    @Slf4j
    @Component
    public class DataFillHandler implements metaObjectHandler {
    	//插入时填充
        @Override
        public void insertFill(metaObject metaObject) {
            log.info("start insert fill....");
            this.setFieldValByName("createDate",new Date(),metaObject);
            this.setFieldValByName("modifyDate",new Date(),metaObject);
        }
    
        //更新时填充
        @Override
        public void updateFill(metaObject metaObject) {
            log.info("start update fill....");
            this.setFieldValByName("modifyDate",new Date(),metaObject);
        }
    }
    

    测试插入

    测试更新

六、条件构造器

多用于复杂SQL
AbstractWrapper有两个子类

1.QueryWrapper

示例:

@Test
public void test1() {
    QueryWrapper wrapper = new QueryWrapper();
    
    wrapper.isNotNull("name") //name字段不等于null
        .isNotNull("email")
        .ge("age", 20);	//age字段大于等于20
    userMapper.selectList(wrapper);
}

@Test
public void test2() {
    QueryWrapper wrapper = new QueryWrapper<>();
    wrapper.eq("name", "Tom");	//name字段等于‘Tom’的记录
    User user = userMapper.selectOne(wrapper);
    System.out.println(user);
}
@Test
public void test3() {
    QueryWrapper wrapper = new QueryWrapper<>();
    wrapper.between("age", 20, 25);	//age字段在20~25区间的记录
    Long count = userMapper.selectCount(wrapper);
    System.out.println(count);
}

@Test
public void test4() {
    QueryWrapper wrapper = new QueryWrapper<>();
    wrapper.notLike("name", "a")	//模糊查询不包含‘a’的记录
        .likeRight("email", "3");	//模糊查询
    userMapper.selectList(wrapper);
}
@Test
public void test5() {
    QueryWrapper wrapper = new QueryWrapper<>();
    wrapper.inSql("id", "select id from user where age > 22");	//子查询的id与父查询id匹配
    userMapper.selectList(wrapper);
}

@Test
public void test6() {
    QueryWrapper wrapper = new QueryWrapper<>();
    wrapper.orderByDesc("id");	//将ID降序排序
    userMapper.selectList(wrapper);
}

2.UpdateWrapper

示例:

@Test
public void test7(){
    UpdateWrapper wrapper = new UpdateWrapper<>();
    //批量更新 ID为2,3 的记录字段name为‘张三
    wrapper.set("name","张三")
        .in("id", Arrays.asList(2,3));
    userMapper.update(new User(),wrapper);
}
七、代码自动生成器

具体参考:Mybatis-plus最新代码生成器(3.5.1+)的使用
示例:

public class GeneratorCode {
	private static String url = "jdbc:mysql://localhost:3306/club?useSSL=false&useUnicode=true&characterEncoding=utf-8";
	private static String username = "root";
	private static String password = "admin";
	public static void main(String[] args) {
		List tables = new ArrayList<>();
        tables.add("blog");
        FastAutoGenerator.create(url,username,password)
                .globalConfig(builder -> {
                    builder.author("mr.ck")               //作者
                            .outputDir("E:\code\JavaIDEA\自学\mybatis-plus\mybatis-plus-generator\src\main\java")    //输出路径(写到java目录)
                            .enableSwagger()           //开启swagger
                            .commentDate("yyyy-MM-dd")
                            .fileOverride();            //开启覆盖之前生成的文件

                })
                .packageConfig(builder -> {
                    builder.parent("com.cheng.mybatisplusgenerator")
                            .moduleName("generator")
                            .entity("entity")
                            .service("service")
                            .serviceImpl("serviceImpl")
                            .controller("controller")
                            .mapper("mapper")
                            .xml("mapper")
                            .pathInfo(Collections.singletonMap(OutputFile.mapperXml,"E:\code\JavaIDEA\自学\mybatis-plus\mybatis-plus-generator\src\main\resources\mapper"));
                })
                .strategyConfig(builder -> {
                    builder.addInclude(tables)
                            .addTablePrefix("t_")
                            .serviceBuilder()
                            .formatServiceFileName("%sService")
                            .formatServiceImplFileName("%sServiceImpl")
                            .entityBuilder()
                            .enableLombok()
                            .logicDeleteColumnName("deleted")
                            .enableTableFieldAnnotation()
                            .controllerBuilder()
                            .formatFileName("%sController")
                            .enableRestStyle()
                            .mapperBuilder()
                            .enablebaseResultMap()  //生成通用的resultMap
                            .superClass(baseMapper.class)
                            .formatMapperFileName("%sMapper")
                            .enableMapperAnnotation()
                            .formatXmlFileName("%sMapper");
                })
                .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
                .execute();
	}
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/731639.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号