• MyBatisPlus笔记


    文章目录

    1. 快速入门

    1.1 新建模块,导入依赖

    1. 起步依赖,MybatisPuls,lombok,mysql驱动,druid数据源

    1.2 编写mapper接口

    1. 编写实体类
    2. 编写接口继承BaseMapperextends BaseMapper<实体类>
    public interface UserMapper extends BaseMapper<User> {
    }
    
    • 1
    • 2

    1.3 编写启动类

    @SpringBootApplication
    //扫描接口所在包(放入容器中)
    @MapperScan("com.itheima.mapper")
    public class Springboot07MpApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(Springboot07MpApplication.class, args);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    1.4 CRUD测试

    @SpringBootTest
    class Springboot07MpApplicationTests {
    
        //注入接口
        @Autowired
        UserMapper userMapper;
    
        //查询所有
        @Test
        void findAll() {
            List<User> users = userMapper.selectList(null);
            for (User user : users) {
                System.out.println(user);
            }
        }
        //根据id查询
        @Test
        void findById() {
            User user = userMapper.selectById(1);
            System.out.println(user);
        }
    
        //增     id会发生类型不匹配的问题
        @Test
        void save() {
            User user = new User();
            user.setName("李想");
            user.setPassword("123456");
            user.setAge(18);
            user.setTel("123");
            int row = userMapper.insert(user);
            System.out.println("row = " + row);
        }
    
        //改
        @Test
        void update() {
    
            User user = userMapper.selectById(1556120358787059714L);
            user.setName("李晓");
            user.setTel("123456");
    
            int row = userMapper.updateById(user);
            System.out.println("row = " + row);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    1.5 注意点

    使用MP封装的方法进行自增时,自增返回的主键需要使用Long封装类型的id,

    3. 分页查询

    3.1 编写mp配置类

    @Configuration
    public class MyBatisPlusConfig {
    
        @Bean
        public MybatisPlusInterceptor mybatisPlusInterceptor() {
    
            //创建mp拦截器
            MybatisPlusInterceptor mpi = new MybatisPlusInterceptor();
    
            //创建分页插件
            mpi.addInnerInterceptor(new PaginationInnerInterceptor());
    
            return mpi;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3.2 API使用

    创建分页对象,使用有参方法

    Page page = new Page<>(1, 3);

    调用分页查询方法(参数1:page对象,参数2:查询器对象(查询条件))

    userMapper.selectPage(page,null);

    //分页查询
        @Test
        void pageTest() {
    
            //1.创建分页对象
            Page<User> page = new Page<>(1, 3);
    
            //2.分页查询
            userMapper.selectPage(page,null);
    
            System.out.println("当前页是第:" + page.getCurrent()+"页");
            System.out.println("每页显示条数:" + page.getSize());
            System.out.println("当前页数据" + page.getRecords());
            System.out.println("总页数:" + page.getPages());
            System.out.println("总条数:" + page.getTotal());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    4. 日志配置

    4.1 开启mp的日志(sql语句输出到控制台)

    # 开启mp的日志(sql语句输出到控制台)
    mybatis-plus:
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    
    • 1
    • 2
    • 3
    • 4

    4.2 解决日志打印过多问题

    1. 新建一个logback.xml文件

    
    <configuration>
    
    configuration>
    
    • 1
    • 2
    • 3
    • 4

    关于logback参考播客:https://www.jianshu.com/p/75f9d11ae011

    4.2 关闭控制台springboot图标

    spring:
      main:
        banner-mode: off # 关闭SpringBoot启动图标(banner)
    
    • 1
    • 2
    • 3

    4.3 关闭控制台mp的图标

    注:关闭语句和mp控制台日志同级

    # mybatis-plus日志控制台输出
    mybatis-plus:
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
        
      global-config:
        banner: off # 关闭mybatisplus启动图标
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    5. 条件查询

    5.1 方式一(查年龄小于18的数据)

    //条件查询
        @Test
        void queryWrapperTest() {
    
            //创建查询器
            QueryWrapper<User> qw = new QueryWrapper<>();
            //(数据库中的列名,条件)
            qw.lt("age", 18);
    
            List<User> users = userMapper.selectList(qw);
            for (User user : users) {
                System.out.println("user = " + user);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    5.2 方式二(查年龄小于18的数据)

    		//创建查询器
            QueryWrapper<User> qw = new QueryWrapper<>();
            qw.lambda().lt(User::getAge, 10);
    
            List<User> users = userMapper.selectList(qw);
            for (User user : users) {
                System.out.println("user = " + user);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    5.3 方式三(查年龄小于18的数据)

            //创建查询器
            LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
            lqw.lt(User::getAge, 18);
    
            List<User> users = userMapper.selectList(lqw);
            for (User user : users) {
                System.out.println("user = " + user);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    5.4 或者查询(默认并且)

            //小于10或者大于25		
            //或者
            LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
            lqw.lt(User::getAge, 10).or().gt(User::getAge, 25);
    
            List<User> users = userMapper.selectList(lqw);
            for (User user : users) {
                System.out.println("user = " + user);
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    5.5 模拟登录

    		//账户和密码正确才可登录
    		LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
            lqw.eq(User::getName, "李晓").eq(User::getPassword, "123");
    
            User user = userMapper.selectOne(lqw);
            System.out.println("user = " + user);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    5.6 QueryWrapper方法与功能

    常用方法

    方法功能备注
    eq指定列的值相同equals的简写
    ne指定列的值不相同not equals的简写
    lt指定列的值小于less then的简写
    le指定列的值小于等于less then and equals的简写
    gt指定列的值大于great then 的简写
    ge指定列的值大于等于great then and equals的简写
    between指定列的值在…和…之间
    notBetween指定列的值不在…和…之间
    like指定列的值等值模糊查询
    notLIke指定列的值不等值模糊查询
    orderByAsc按照指定的列升序排序
    orderByDesc按照指定的列降序排序
    groupBy按照指定的列分组
    having按照指定的列在分组后条件过滤
    in单条件多值查询
    isNull指定列的值为空
    isNOtNull指定列的值不为空

    6. 模糊查询

    		LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
    		//左右都模糊
            lqw.like(User::getName, "张");
    
            List<User> users = userMapper.selectList(lqw);
            for (User user : users) {
                System.out.println("user = " + user);
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    7. 聚合查询

    		QueryWrapper<User> qw = new QueryWrapper<>();
            //聚合的列(密码,个数)
            //聚合的条件,根据密码的不同
            qw.select("password", "count(*) as nums").groupBy("password");
    
            List<Map<String, Object>> maps = userMapper.selectMaps(qw);
            for (Map<String, Object> map : maps) {
                System.out.println("map = " + map);
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    8. 条件查询的null值处理

    		HashMap<String, Integer> map = new HashMap<>();
            //map.put("min", 8);
            map.put("max", 18);
    
            LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
    
            Integer min = map.get("min");
            Integer max = map.get("max");
    
            //如果为null,不执行此条件
            lqw.ge(min != null, User::getAge, 8);
            lqw.le(User::getAge, 18);
    
            List<User> users = userMapper.selectList(lqw);
            for (User user : users) {
                System.out.println("user = " + user);
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    9. 投影映射(查询指定的列)

    1.方式一

    		//创建查询器对象
            LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
    
            //创建查询条件
            lqw.select(User::getName, User::getAge, User::getTel);
    
            List<User> users = userMapper.selectList(lqw);
            for (User user : users) {
                System.out.println("user = " + user);
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2. 方式二

    		//创建查询器对象
            QueryWrapper<User> qw = new QueryWrapper<>();
    
            //创建查询条件
            qw.select("name", "age");
    
            List<User> users = userMapper.selectList(qw);
            for (User user : users) {
                System.out.println("user = " + user);
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    10 类库不一致

    1. 常用注解

    //指定表名		(解决表名和类名不一致)
    @TableName("t_user")
    public class User {
        
        private Long id;
        //@TableField("表中字段")	(解决表字段和实体类属性名不一致)
        @TableField("username")
        //实体类属性
        private String name;
        //mp自动开启了驼峰映射
        //不参与查询,但是不影响其他操作,只是对查询有影响
        @TableField(select = false)
        private String passWord;
        private Integer age;
        private String tel;
        
        //该变量不参与数据库的CRUD
        @TableField(exist = false)
        private String online;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2. 注意:

    1. mp自动开启驼峰命名

      mybatis-plus:
        configuration:
          # 自动开启驼峰映射
          map-underscore-to-camel-case: true
      
      • 1
      • 2
      • 3
      • 4

    11. 增删改DML

    1. 增:主键生成策略

    1.1 不同的表的id生成策略不同

    • 日志/常规简单:整型自增(1,2,3,4,……)
    • 购物订单:特殊规则(FQ23948AK3843)
    • 外卖单:关联地区日期等信息(10 04 20200314 34 91)
    • 关系表:可省略id

    1.2 常见的生成策略

    • 五种可用,三种已过期。详情如下:
      • AUTO(0):使用数据库id自增策略控制id生成
      • NONE(1):不设置id生成策略
      • INPUT(2):用户手工输入id
      • ASSIGN_ID(3):雪花算法生成id(可兼容数值型与字符串型)
      • ASSIGN_UUID(4):以UUID生成算法作为id生成策略

    1.3 用法

    1. 使用注解
    public class User {
    
        //自增
        @TableId(type = IdType.AUTO)
        private Long id;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 全局策略配置
    mybatis-plus:
      global-config:
        db-config:
          # 全局配置使用雪花算法	可替换(@TableId(type = IdType.AUTO))
          id-type: auto
          # 表的前缀 可替换(@TableName("t_user"))
          table-prefix: t_
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2. 删

    2.1 物理删除

    1.按照主键删除批量删除

    //删除指定多条数据
    List<Long> list = new ArrayList<>();
    list.add(1402551342481838081L);
    list.add(1402553134049501186L);
    list.add(1402553619611430913L);
    
    userDao.deleteBatchIds(list);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2. 根据主键查询多条记录

    //查询指定多条数据
    List<Long> list = new ArrayList<>();
    list.add(1L);
    list.add(3L);
    list.add(4L);
    userDao.selectBatchIds(list);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.2 逻辑删除

    本质:逻辑删除的本质其实是修改操作。如果加了逻辑删除字段,查询数据时也会自动带上逻辑删除字段

    前提:要在数据库中添加响应字段

    方式一:

    	//逻辑删除字段,标记当前记录是否被删除
        // value表示未删除,delval表示已删除
        @TableLogic(value="0", delval="1")
        private Integer deleted;
    
    • 1
    • 2
    • 3
    • 4

    方式二:

    mybatis-plus:
      global-config:
        db-config:
          table-prefix: tbl_
          # 逻辑删除字段名
          logic-delete-field: deleted
          # 逻辑删除字面值:未删除为0
          logic-not-delete-value: 0
          # 逻辑删除字面值:删除为1
          logic-delete-value: 1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3. 改(乐观锁)

    悲观锁:假设最坏地情况必定会发生,为了避免这种情况发生,我从一开始就给他杜绝了。(Synchronized

    乐观锁:总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不用上锁。

    ​ 只在更新的时候会判断一下在此期间别人有没有去更新这个数据。

    3.1 乐观锁实现思路

    1. 使用数据版本(Version)记录:
      • 这最常用的一种实现方式。为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 version字段来实现。
      • 当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加1
      • 更新后,当前记录的版本信息和之前查询时取出的版本号进行对比,如果相等更新;否则放弃修改或者重新查询一次再进行修改
    2. 使用时间戳记录

    3.2 乐观锁实现步骤

    1. 数据库表中添加锁标记字段(vension)

    2. 实体类中添加对应字段,并设定当前字段为逻辑删除标记字段

    	@Version
        private Integer version;
    
    • 1
    • 2

    3. 配置乐观锁拦截器实现锁机制对应的动态SQL语句拼装

    @Configuration
    public class MpConfig {
        @Bean
        public MybatisPlusInterceptor mpInterceptor() {
            //1.定义Mp拦截器
            MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
    
            //2.添加乐观锁拦截器
            mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
            
            return mpInterceptor;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    4. 使用乐观锁机制在修改前必须先获取到对应数据的verion方可正常进行

    //1.先通过要修改的数据id将当前数据查询出来
        User user = userDao.selectById(3L);     //version=3
        User user2 = userDao.selectById(3L);    //version=3
        user2.setName("Jock aaa");
        userDao.updateById(user2);              //version=>4
        user.setName("Jock bbb");
        userDao.updateById(user);               //verion=3?条件还成立吗?
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    执行前先执行查询语句

    执行修改时使用vesion字段作为乐观锁的检查依据

  • 相关阅读:
    Kafka消息存储
    计算机毕业设计Java校园服装租赁系统(系统+源码+mysql数据库+lw文档)
    Java&Excel:自动生成数据表并插入数据
    基于PHP使用influxdb搭建监控服务系统
    ATE测试工程师的薪资前景如何?能转DFT工程师吗?
    mp4压缩视频不改变画质?跟我这样压缩视频大小
    【optimtool.unconstrain】无约束优化工具箱
    【精品】Springboot 接收发送日期类型的数据
    Linux 下查看 VNC 连接状态
    web前端三大主流框架
  • 原文地址:https://blog.csdn.net/weixin_50707328/article/details/126222788