MybatisPlus(2)

SpringBoot 如何集成 MyBatisPlus - SpringBoot 2.7.2实战基础 SpringBoot 2.7.2 学习系列,本节通过实战内容讲解如何集成 MyBatisPlus 阅读详情

4 条件构造器

警告:
不支持以及不赞成在 RPC 调用中把 Wrapper 进行传输

  1. wrapper 很重
  2. 传输 wrapper 可以类比为你的 controller 用 map 接收值(开发一时爽,维护火葬场)
  3. 正确的 RPC 调用姿势是写一个 DTO 进行传输,被调用方再根据 DTO 执行相应的操作

4.1 wrapper介绍

在这里插入图片描述
带Query字样的是查询用,带Update字样的是update用,带Lambda字样的是可以用Lambda语法的类。

4.2 wrapper使用样例

条件构造器所有使用参见官方文档:https://baomidou.com/pages/10c804/

	@Autowired
    private UserMapper userMapper;

    @Test
    void test1() {//like()、between()、isNotNull()
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //查询name包含a,年龄20-30,邮箱不为null的users
        wrapper.like("user_name", "a").between("age", 20, 30).isNotNull("email");
        //==>  Preparing: SELECT user_id,user_name AS name,age,email,is_deleted FROM user WHERE is_deleted=0 AND (user_name LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)
        //==> Parameters: %a%(String), 20(Integer), 30(Integer)
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }

    @Test
    void test2() {//orderByDesc()、orderByAsc()
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //查询,按照年龄降序,年龄相同按照id升序。
        wrapper.orderByDesc("age").orderByAsc("user_id");
        //==>  Preparing: SELECT user_id,user_name AS name,age,email,is_deleted FROM user WHERE is_deleted=0 ORDER BY age DESC,user_id ASC
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }

    @Test
    void test3() {//delete
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //删除邮箱为null的users
        wrapper.isNull("email");
        //==>  Preparing: UPDATE user SET is_deleted=1 WHERE is_deleted=0 AND (email IS NULL)
        userMapper.delete(wrapper);
    }

    @Test
    void test4() {//or()、gt()
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //将(age>20且user_name包含a)或者(email不为null)的用户修改
        wrapper.gt("age", 20).like("user_name", "a")
                .or()
                .isNotNull("email");
        //修改为name=xiaoming
        User user = new User();
        user.setName("xiaoming");
        //==>  Preparing: UPDATE user SET user_name=? WHERE is_deleted=0 AND (age > ? AND user_name LIKE ? OR email IS NOT NULL)
        //==> Parameters: xiaoming(String), 20(Integer), %a%(String)
        userMapper.update(user, wrapper);//(修改值实体类,被修改对象wrapper)
    }

    @Test
    void test5() {//查询条件的优先级、and()
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //注意和test4的情况区分,lambda表达式的条件优先执行
        //将age>20且(user_name包含a或者email不为null)的用户查找
        wrapper.gt("age", 20)
                .and(i -> i.like("name", "a")
                        .or()
                        .isNotNull("email")
                );
        //==> Preparing: SELECT id,name,age,email,is_deleted FROM user WHERE is_deleted=0 AND (age > ? AND (name LIKE ? OR email IS NOT NULL))
        //==> Parameters: 20(Integer), %a%(String)
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }

    @Test
    void test6() {//部分查询
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //部分查询,只查id和name
        wrapper.select("id", "name");
        //==>  Preparing: SELECT id,name FROM user WHERE is_deleted=0
        List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
        System.out.println(maps);
    }

    @Test
    void test7() {//UpdateWrapper<>()使用、ge()
        UpdateWrapper<User> wrapper = new UpdateWrapper<>();

        //修改对象:age>20
        wrapper.ge("age", 20);
        //修改值:name=zhangsan
        wrapper.set("name", "zhangsan");
        //==>  Preparing: UPDATE user SET name=? WHERE is_deleted=0 AND (age >= ?)
        //==> Parameters: zhangsan(String), 20(Integer)
        userMapper.update(null, wrapper);
    }

    @Test
    void test08() {//根据条件是否符合要求,组装条件进行查询、le()
        String name = "";
        Integer ageMin = 20;
        Integer ageMax = 30;
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //StringUtils.isNotBlank(name):name不为null和空
        wrapper.like(StringUtils.isNotBlank(name), "name", name).ge(ageMin != null, "age", ageMin).le(ageMax != null, "age", ageMax);
        //==> Preparing: SELECT id,name,age,email,is_deleted FROM user WHERE is_deleted=0 AND (age >= ? AND age <= ?)
        //==> Parameters: 20(Integer), 30(Integer)
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);

    }


    @Test
    void test09() {//LambdaQueryWrapper<>()
        String name = "";
        Integer ageMin = 20;
        Integer ageMax = 30;
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        //StringUtils.isNotBlank(name):name不为null和空
        wrapper.like(StringUtils.isNotBlank(name), User::getName, name)
                //第二个参数非lambda情况下是要写数据库字段名的,但有可能忘记字段名
                //lambda情况下直接写属性名,让它自己去映射,博主感觉很nice,不用再记属性-字段怎么对应的
                .ge(ageMin != null, User::getAge, ageMin)
                .le(ageMax != null, User::getAge, ageMax);
        //==> Preparing: SELECT id,name,age,email,is_deleted FROM user WHERE is_deleted=0 AND (age >= ? AND age <= ?)
        //==> Parameters: 20(Integer), 30(Integer)
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }

    @Test
    void test10() {//LambdaUpdateWrapper<>()
        LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(User::getId, 1);
        wrapper.set(User::getEmail, "update@qq.com");
        //==> Preparing: UPDATE user SET email=? WHERE is_deleted=0 AND (id = ?)
        //==> Parameters: update@qq.com(String), 1(Integer)
        userMapper.update(null, wrapper);
    }

5 mybatisplus插件:分页、乐观锁

5.1 分页插件

首先配置分页插件,顺便把@MapperScan也从启动类上拿过来:

package com.coderhao.mybatisplus.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("com.coderhao.mybatisplus.mapper")
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return mybatisPlusInterceptor;
    }
}

使用:

	@Test
    void test1(){
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        String name="a";
        wrapper.like(StringUtils.isNotBlank(name),User::getName,name);
        Page<User> page = new Page<>(2,3);//第2页,每页显示3条数据
        //==>  Preparing: SELECT COUNT(*) FROM user WHERE is_deleted = 0 AND (name LIKE ?)
        //==> Parameters: %a%(String)
        //==>  Preparing: SELECT id,name,age,email,is_deleted FROM user WHERE is_deleted=0 AND (name LIKE ?) LIMIT ?,?
        //==> Parameters: %a%(String), 3(Long), 3(Long)
        //分页数据会回显到page里
        userMapper.selectPage(page, wrapper);
        page.getRecords().forEach(System.out::println);
    }

5.2 乐观锁

作用:防止出现第一类和第二类更新丢失。(更新丢失:两个事务操作同一个数据,后提交/回滚的事务覆盖了先提交的事务。)
乐观锁使用version字段来解决该问题,提交/回滚时检查数据版本,如果更改时数据版本不是一开始取出时的版本,则该操作不生效。
悲观锁则是事务阻塞,一个事务在执行,另一个事务则不能执行。
在这里插入图片描述
注意:这里有一个坑!一定要先查询出这条数据,再更新,乐观锁才会生效!!!
在这里插入图片描述
更新丢失可以通过开两个线程,2个线程都对同一数据进行操作,看结果是否符合预期(比如一个线程把一个数据+1,循环500次,另一个-1,循环500次,看结果是不是不变)。

(1)乐观锁配置

mybatisplus的配置类里填上乐观锁组件:

	@Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());//添加乐观锁组件
        return mybatisPlusInterceptor;
    }

(2)创建数据库表、实体类、mapper

表(因为我们这个emp_salary字段是个金融数字,所以用精确的decimal类型):

CREATE TABLE `emp` (
  `emp_id` bigint NOT NULL AUTO_INCREMENT COMMENT '员工id',
  `emp_salary` decimal(10,0) DEFAULT NULL COMMENT '员工工资',
  `emp_version` bigint DEFAULT '0' COMMENT '乐观锁版本号',
  `is_deleted` int DEFAULT '0' COMMENT '逻辑删除',
  PRIMARY KEY (`emp_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb3

填两个数据:
在这里插入图片描述
实体类,注意 @Version注解和BigDecimal类型:

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("emp")
public class Emp {
    @TableId(value = "emp_id",type = IdType.AUTO)
    private Long empId;
    @TableField("emp_salary")
    private BigDecimal empSalary;
    @Version//乐观锁需要的版本号
    private Long empVersion;
    @TableLogic
    private Integer isDeleted;
}

EmpMapper:

public interface EmpMapper extends BaseMapper<Emp> {
}

(3)测试

注意BigDecimal类型的运算方式

@Test
    void test2(){
        LambdaQueryWrapper<Emp> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Emp::getEmpId,1L);
        Emp emp = empMapper.selectOne(wrapper);
        emp.setEmpSalary(emp.getEmpSalary().add(BigDecimal.valueOf(1L)));
        //==>  Preparing: UPDATE emp SET emp_salary=?, emp_version=? WHERE is_deleted=0 AND (emp_id = ? AND emp_version = ?)
        //==> Parameters: 5001(BigDecimal), 1(Long), 1(Long), 0(Long)
        empMapper.update(emp,wrapper);
    }

发现版本号变了,而且更新过程中sql语句也有判断版本号的情况。
在这里插入图片描述

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

6 通用枚举:@EnumValue+枚举包扫描

数据库表中有很多字段的值是固定的几个里面选一个:比如性别(男女选一)。
这里还是以emp表为例,加个emp_sex:
在这里插入图片描述
搞个枚举类,注意@EnumValue,这个标注的是真正往数据库里放的值:

package com.coderhao.mybatisplus.enums;

import com.baomidou.mybatisplus.annotation.EnumValue;
import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
@Getter
public enum SexEnum {
    //设置枚举的内容
    MALE(1,"男"),
    FEMALE(0,"女");
    //枚举的属性
    @EnumValue
    private Integer sex;
    private String sexName;
}

Emp,加个枚举类型的属性:

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("emp")
public class Emp {
    @TableId(value = "emp_id",type = IdType.AUTO)
    private Long empId;
    @TableField("emp_salary")
    private BigDecimal empSalary;
    @Version//乐观锁需要的版本号
    private Long empVersion;
    @TableLogic
    private Integer isDeleted;
    @TableField("emp_sex")
    private SexEnum empSex;
}

yaml里面枚举包扫描:

mybatis-plus:
  # 扫描通用枚举包
  type-enums-package: com.coderhao.mybatisplus.enums

测试:

	@Test
    void test3(){
        Emp emp = new Emp(null,BigDecimal.valueOf(4000L),null,null, SexEnum.MALE);
        empMapper.insert(emp);
    }

有数据,枚举类型填了相应的值,而且其他字段也有默认值。
在这里插入图片描述

7 代码生成器

mybatisplus的代码生成器可以由表生成entity,controller,service,mapper,mapper.xml
虽然这里讲代码生成器,但博主不建议用代码生成器,MP的功能已经很强大了,没必要代码生成,何况生成的controller,service层可能也不满意,实体类也缺逻辑删除和乐观锁的注解。

(1)创建案例表

CREATE TABLE `pre_table_name_one` (
  `t_id` bigint NOT NULL AUTO_INCREMENT,
  `t_name` varchar(30) DEFAULT NULL,
  `t_date` datetime DEFAULT NULL,
  `t_salary` decimal(10,0) DEFAULT NULL,
  `t_is_deleted` int DEFAULT '0',
  `t_version` bigint DEFAULT '0',
  PRIMARY KEY (`t_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3

搞两个数据:
在这里插入图片描述

(2)引入依赖,配置代码生成器

		<!--代码生成器依赖包-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.5.1</version>
        </dependency>
        <!--模板引擎-->
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.31</version>
        </dependency>
        <!--生成的controller层要这个包依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

代码生成器配置:

@SpringBootTest
public class MPG {
    @Value("${spring.datasource.url}")
    private String url;
    @Value("${spring.datasource.username}")
    private String username;
    @Value("${spring.datasource.password}")
    private String password;

    @Test
    void test1() {

        FastAutoGenerator.create(url, username, password)
                //全局配置
                .globalConfig(builder -> {
                    builder.author("coderhao") // 设置作者
//                            .enableSwagger() // 开启 swagger 模式
                            .fileOverride() // 覆盖已生成文件
                            .outputDir("F://project//learn//boot-mybatisplus//src//main//java//"); // 指定输出目录
                })
                //包配置
                .packageConfig(builder -> {
                    builder.parent("com.coderhao") // 设置父包名
                            .moduleName("mybatisplus") // 设置父包模块名
                            .pathInfo(Collections.singletonMap(OutputFile.mapperXml, "F://project//learn//boot-mybatisplus//src//main//resources//mapper//tableName//")); // 设置mapperXml生成路径
                })
                //策略配置
                .strategyConfig(builder -> {
                    builder.addInclude("pre_table_name_one") // 设置需要生成的表名
                            .addTablePrefix("pre_", "c_"); // 设置过滤表前缀
                })
                .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
                .execute();
    }
}
  • java代码最终路径是:
    outputDir+parent+moduleName,在这个路径下面是controller/serivce/entity/mapper等包
  • mapper.xml路径:
    pathInfo那个里面的路径

注:可以看到生成的东西:
在这里插入图片描述
其中,实体类没有逻辑删除和乐观锁的注解。

(3)测试

有个小bug,实体类中用到了LocalDateTime类型,查询时数据转换为实体类时报错,把druid的版本弄成1.1.22就行了。

	@Autowired
    private ITableNameOneService tableNameOneService;
    @Autowired
    private TableNameOneMapper tableNameOneMapper;
    
	@Test
    void test2() {
        List<TableNameOne> list = tableNameOneService.list();
        list.forEach(System.out::println);
    }

    @Test
    void test3() {
        TableNameOne tableNameOne = new TableNameOne();
        tableNameOne.settName("name3");
        tableNameOneMapper.insert(tableNameOne);
    }

8 多数据源管理

(1)创建案例库/表

数据表很可能分布在多个数据库中,就需要多数据源管理。
读写分离就是在保持主从库的数据一致性的情况下,主库写,从库读。
创建一个新库叫testdb2,创建一个同样的数据表emp,加两条数据:

CREATE TABLE `emp` (
  `emp_id` bigint NOT NULL AUTO_INCREMENT COMMENT '员工id',
  `emp_salary` decimal(10,0) DEFAULT NULL COMMENT '员工工资',
  `emp_version` bigint DEFAULT '0' COMMENT '乐观锁版本号',
  `is_deleted` int DEFAULT '0' COMMENT '逻辑删除',
  `emp_sex` int DEFAULT '0' COMMENT '性别,只有0/1',
  PRIMARY KEY (`emp_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb3

在这里插入图片描述

(2)引入依赖,配置yaml

		<dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>3.5.0</version>
        </dependency>

yaml数据源改成这样:

spring:
  datasource:
    dynamic:
      primary: master #设置默认的数据源或者数据源组,默认值即为master
      strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
      datasource:
        master:
          url: jdbc:mysql://localhost:3306/testdb?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
          username: root
          password: password
          driver-class-name: com.mysql.cj.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
        slave_1:
          url: jdbc:mysql://localhost:3306/testdb2?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
          username: root
          password: password
          driver-class-name: com.mysql.cj.jdbc.Driver
        #以上会配置一个默认库master,一个组slave下有1个子库slave_1

(3)@DS切换数据库

package com.coderhao.mybatisplus.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.coderhao.mybatisplus.mapper.EmpMapper;
import com.coderhao.mybatisplus.pojo.Emp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class MDSimpl {
    @Autowired
    private EmpMapper empMapper;

    //添加@DS注解到实现类或者实现类的方法上才可以,同时存在就近原则 方法上注解 优先于 类上注解,测试类发现不太行,不知道为啥
    //不加@DS就是默认数据库
    @DS("master")
    public void f1() {
        List<Emp> emps = empMapper.selectList(null);
        emps.forEach(System.out::println);
    }

	//@DS("slave_1")
    @DS("slave")//组名或者具体库名都行
    public void f2() {
        List<Emp> emps = empMapper.selectList(null);
        emps.forEach(System.out::println);
    }
}

(4)测试

	@Autowired
    private MDSimpl mdSimpl;

    @Test
    void test1(){
        mdSimpl.f1();
        mdSimpl.f2();
    }

9 MybatisX插件

idea平台独有的插件,可以解决一些复杂sql、多表联查问题。
这个插件的功能博主写这篇文章的时候觉得还行。

9.1 安装插件

在这里插入图片描述
安装后重启idea。

9.2 功能描述

(1)xml与mapper的跳转。

点击小鸟实现跳转。
在这里插入图片描述
在这里插入图片描述

(2)代码生成器

  1. idea连上数据库:
    在这里插入图片描述
    在这里插入图片描述
  2. 代码生成器配置
    先把之前MPG代码生成的删除,重新用这个生成。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    生成的代码文件,没有controller层:
    在这里插入图片描述
  3. 补充实体类注解
package com.coderhao.mybatisplus.pojo;

import com.baomidou.mybatisplus.annotation.*;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;

@TableName(value ="pre_table_name_one")
@Data
public class TableNameOne implements Serializable {
    @TableId(value = "t_id",type = IdType.AUTO)
    private Long id;

    @TableField("t_name")
    private String name;

    @TableField("t_date")
    private Date date;

    @TableField("t_salary")
    private Integer salary;

    @TableField("t_is_deleted")
    @TableLogic
    private Integer isDeleted;
    
    @TableField("t_version")
    @Version
    private Long version;

    @TableField(exist = false)
    //博主推测这个设置代替数据库中的版本字段设置初始值
    private static final long serialVersionUID = 1L;
}
  1. 测试
	@Autowired
    private TableNameOneService tableNameOneService;
    @Autowired
    private TableNameOneMapper tableNameOneMapper;
    
	@Test
    void test2() {
        List<TableNameOne> list = tableNameOneService.list();
        list.forEach(System.out::println);
    }

    @Test
    void test3() {
        TableNameOne tableNameOne = new TableNameOne();
        tableNameOne.setName("name4");
        tableNameOneMapper.insert(tableNameOne);
    }

    @Test
    void test4(){
        tableNameOneMapper.deleteById(1);
        test2();
    }

    @Test
    void test5(){
        LambdaQueryWrapper<TableNameOne> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TableNameOne::getId,2);
        TableNameOne tableNameOne = tableNameOneMapper.selectOne(wrapper);
        tableNameOne.setSalary(4444);
        tableNameOneMapper.update(tableNameOne,wrapper);
    }

(3)快速生成crud

可以根据mapper的方法快速生成crud。
这里用选择性的条件添加来做例子。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看到方法巨多,而且都挺常用的,生成一些复杂的也不在话下,经典前面白学:
在这里插入图片描述
增删改查例子,根据提示来写,易上手,太强了:

public interface TableNameOneMapper extends BaseMapper<TableNameOne> {

    //添加
    int insertSelective(TableNameOne tableNameOne);
    //按照id在区间内查找
    List<TableNameOne> selectAllByIdBetween(@Param("beginId") Long beginId, @Param("endId") Long endId);
    //更新name,salary(按照salary在区间内和时间等于某值)
    int updateNameAndSalaryBySalaryBetweenAndDate(@Param("name") String name, @Param("salary") Integer salary, @Param("beginSalary") Integer beginSalary, @Param("endSalary") Integer endSalary, @Param("date") Date date);
    //删除从某个时候之后的
    int deleteByDateAfter(@Param("date") Date date);
}
在Jetson Orin (Arm64)上从Ubuntu22.04回退至20.04的完整指南及ROS-noetic适配方案 本文提供了在Jetson Orin (Arm64)设备上将Ubuntu 22.04系统回退至20.04 LTS版本的完整操作指南。针对机器人开发中ROS-noetic对Ubuntu20.04的官方最佳支持,详细阐述了从关键备份、软件源与APT优先级配置、系统降级执行到后续问题排查的全过程,并附带了在Arm64架构上成功安装和验证ROS-noetic的适配方案,旨在为开发者构建稳定可靠的机器人开发环境。 阅读详情

相关推荐

当迁移学习遇见室内定位:基于UJIIndoorLoc的跨场景适配实践

本文探讨了迁移学习在跨建筑室内定位中的应用,重点解析了UJIIndoorLoc数据集的特性及其在解决设备差异和环境变化中的关键作用。通过特征工程、迁移学习策略和小样本微调技术,显著提升了定位模型的跨场景适配能力,为实际部署提供了有效解决方案。

weixin_29038155的博客 394

mybatis-plus

文章目录mybatisPlus学习简介案例代码展示核心功能代码生成器CRUD接口条件构造器AbstractWrapperQueryWrapperUpdateWrapper使用分页插件Sequence主键自定义ID生成器扩展逻辑删除自动填充功能Sql 注入器插件乐观锁 mybatisPlus学习 简介 官网地址:https://mp.baomidou.com/ 特性: 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作

admin522043032的博客 622

SAP传输请求全流程详解:从SE10创建到STMS跨环境部署(附常见错误排查)

本文详细解析了SAP传输请求的全流程,从SE10创建到STMS跨环境部署,并提供了常见错误排查方法。涵盖工作台请求、定制请求等类型,以及STMS传输原理和实战操作技巧,帮助用户高效管理SAP系统变更。

weixin_29214335的博客 143

使用dubbo调用mybatisplus方法出现的问题

当在模块中通过dubbo的rpc来调用其他服务的方法时,不能使用mybatisplus的条件构造器wrapper来进行方法调用 因为wrapper中包含有泛型 Wrapper<T> ,会导致rpc解析失败,从而导致调用失败 解决方法:不用wrapper作为参数,自己写方法传递参数就可以。 ...

weixin_39765687的博客 2414

c++多线程(1)------创建和管理线程td::thread

std::thread 是 C++11 标准库中用于创建和管理线程的核心类,定义在 <thread> 头文件中。它使得多线程编程变得简单、类型安全且跨平台。

jndingxin的专栏 648

[OHIF-Viewers]医疗数字阅片-医学影像-cornerstone-core-Cornerstone.js-Cornerstone Examples-基石实例-下...

[OHIF-Viewers]医疗数字阅片-医学影像-cornerstone-core-Cornerstone.js-Cornerstone Examples-基石实例-下 CT Image with Window presets This is an example of displaying a ct image along with buttons to set ww/wc pres...

浩秦的博客 1841

mybatis-plus中wrapper的用法(详细)

mybatis-plus中wrapper的用法,ge、le、ne、eq、及多表查询自写sql

DayDayUp 13万+

麻辣香锅病毒分析

Spicy Hot Pot浏览器劫持病毒(麻辣香锅病毒)从2020年初被安全公司监测到,因其病毒模块带有MLXG_KM被安全行业代称麻辣香锅病毒。目前通过各种激活工具传播, 包括暴风激活、小马激活和KMS激活等诸多工具,疑似与下载站进行合作推广此类激活工具。Spicy Hot Pot 是一个浏览器劫持 Rootkit,它会将用户的主页更改为指向恶意软件操作员控制的页面,此外还会将内存转储从机器上传到预定义的服务器,并结合本地更新功能以确保其保持更新。通常浏览器劫持者会通过更改用户主页的恶意可执行文件或注册表

不忘初心,护天下安全! 4789

【Java开发】 Mybatis-Plus 04:条件构造器-wrapper

大家如果有疑问都可以评论提出,有不足之处请大家批评指正,希望能多结识这方面的朋友,共同学习、共同进步。

尹煜的博客 5232

车辆重识别/再辨识数据集: Vehicle Re-ID Datasets Collection

车辆数据库 1.VERI-Wild: A Large Dataset and a New Method for Vehicle Re-Identification in the Wild (2019-CVPR) 数据库名称:VERI-Wild 论文:链接 数据库描述: 车辆图像由一个包含174个摄像机,拍摄范围覆盖超过200平方公里的市区CCTV系统拍摄。摄像机是24小时连续拍摄30天,其长时间的...

AI炼丹师 6857

AI漫剧全套万能提示词合集

今天给大家整理一套已经跑通爆款漫剧的万能提示词库!覆盖:豆包剧本人设词 + 分镜生成词 + 即梦绘图词 + 动态优化词 + 防翻车固定词直接复制粘贴,新手也能做出稳定、高清、统一、有质感的AI漫剧!你是资深短视频漫剧编剧,擅长制作60秒竖屏爆款AI漫剧,请为我创作一集完整漫剧内容。要求:开头3秒高能抓眼,中段有冲突转折,结尾留强悬念钩子,节奏紧凑、适合短视频流量。首先生成固定统一人物人设:包含脸型、五官、发色、发型、穿搭、身材、气质、画风、光影细节,要求足够精细,保证全程角色不变脸。

欢迎来到鸾姝淡月博客,专为程序员和编程爱好者打造的技术博客。我们分享编程语言趋势、开发工具、编程哲学、职业发展等,助你掌握新技术,优化技能,激发编程热情。 1911

【MyBatis】MyBatis-Plus

学习于baomidou官网:分页插件 | MyBatis-Plus Wrapper 警告⚠️:不支持以及不赞成在 RPC 调用中把 Wrapper 进行传输。 正确的 RPC 调用姿势是写一个 DTO 进行传输,被调用方再根据 DTO 执行相应的操作。 获取LambdaWrapper 在QueryWrapper中是获取LambdaQueryWrapper 在UpdateWrapper中是获取LambdaUpdateWrapper 使用Wrapper自定义SQL 注意事项:需要mybati.

keeper42的博客 1512

手把手教你学基带SOC芯片(4.4.9)--基带芯片的电源管理实例:高通 Snapdragon 系列实例(十)

Snapdragon 888 通过支持多种深度睡眠模式,如 AOAC 模式、低功耗模式和深度睡眠模式,以及智能电源管理技术,实现了对功耗的精细管理。这些模式不仅延长了设备的电池寿命,还确保了用户在各种使用场景下的良好体验。无论是保持网络连接、限制后台活动,还是完全关闭不必要的功能,Snapdragon 888 都能够灵活应对,提供高效的功耗管理方案。

MHD0815的博客 740

SpringBoot2中集成mybatisPlus

在 IDE 中启用(IntelliJ IDEA 或 Eclipse)。确保在 Maven 或 Gradle 项目中添加了正确的 Lombok 依赖,并配置注解处理器。重启 IDE 并重新编译项目。这样就应该能解决的问题。如果还有其他疑问,随时问我!在 IDE 中启用(IntelliJ IDEA 或 Eclipse)。确保在 Maven 或 Gradle 项目中添加了正确的 Lombok 依赖,并配置注解处理器。重启 IDE 并重新编译项目。这样就应该能解决的问题。

SAFE20242034的博客 3162

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

【springboot实战】springBoot+mybatisplus+swagger2

这里写自定义目录标题前言实践测试总结 前言 在公司的项目中用到了springboot,用到了swagger2这个api框架,持久层实现是jpa。小编结合项目中的框架,整合一下springboot+mybatisplus+swagger2. 实践 一、在idea里安装lombok和mybatisplus插件。 二、添加pom.xml文件依赖 <dependencies> ...

你若盛开,清风自来 1813

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

mybatisplus 3.2.2报错

mybatisPlus 3.2.2报错

qq_37736994的博客 2576

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

MybatisPlus2与MybatisPlus3 CRUD方法名区别

MybatisPlus 2版本和3版本的CRUD方法名差异

m0_67297673的博客 1234

MybatisPlus 3.3.2的基本使用

这个框架是mybatis的加强版,没有对mybatis侵入 一、基本配置 1、在SpringBoot中引入 <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.0.5</version> </dependency> 2、在配置文

xiangchaoming的博客 2525

SpringBoot2+MybatisPlus配置与生成 极简

SpringBoot2+MybatisPlus 极简 一、新建Spring项目 ​ 结构目录为: [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vdjkf7hB-1604214721044)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201101143305745.png)] ​ 其中DemoApplication为SpringBoot启动类,config用来放配置类 二、

qq_39700719的博客 449

SpringBoot2+mybatisPlus3+activiti6整合,踩的坑

activiti这块骨头终于啃完了,然而刚从坑里爬出来,有一个大坑等着我,在和SprigBoot2和MybatisPlus整合时,有一出现了问题,浪费了一个下午终于把它解决了,在这里做个记录。 SpringBoot2+Activiti6 关于他俩整合相关文档太多,得益于这篇博客,让我我少走很多弯路 https://blog.youkuaiyun.com/qq_22849235/article/detail...

梓隽的博客 7201

MyBatisPlus2

紧接上集 我们配置使用MyBatisPlus完成并且完成了查询,我们这次主要是完成剩下的操作 首先我们先看看还有哪些操作我们没有做呢, 我们进入源码看到还有 /** * Copyright (c) 2011-2020, hubin (jobob@qq.com). * <p> * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in comp

hdnhsf的博客 286

springboot中mybatisplus2和mybatisplus3分页插件使用的区别及注意事项

​springboot中mybatisplus2和mybatisplus3分页插件使用的区别及注意事项 为什么要用分页插件: 在实际工作中,可能有进行列表分页查询的场景,我们往往都需要做两个步骤:1. 查询所需页数对应数据;2. 统计符合条件的数据总数;而这,又会导致我们必然至少要写2个sql进行操作。这无形中增加了我们的工作量,另外,当发生需要变动时,我们又需要同时改动这两个sql,否则必然导致结果的不一致。并且,如果出现有数据库迁移的情况下,写的sql分页方式肯定又需要进行大量修改,此时引入分页插件自动

qq_27577113的博客 2407

SpringBoot集成Swagger2+MybatisPlus逆向工程生成Swagger2注解

swagger使用指南

luck_sheng的博客 2571

基于maven把struts2项目升级为SpringBoot2.0+MybatisPlus项目

基于maven把struts2项目升级为SpringBoot2.0+MybatisPlus项目修改pom添加SpringBoot配置文件常见问题(待补) 修改pom 1.升级spring全家桶到5.0以上(spring-web,spring-webmvc,spring-tx,spring-jdbc,spring-expression,spring-core,spring-context-support,spring-context,spring-beans,spring-aspects,spring-aop

不忘初心,继续前进 3691

MyBatisPlus逻辑删除IndexTTS2任务记录而非物理删除

在IndexTTS2这类AI语音服务平台中,任务记录承载着重要业务与模型反馈数据。通过MyBatisPlus的@TableLogic注解和全局配置,实现删除操作的“软隐藏”,避免物理删除导致的数据丢失。查询自动过滤已删记录,开发无感接入,同时支持后续审计、恢复与数据分析,提升系统容错性与合规能力。

weixin_35749796的博客 321

MyBatisPlus最新的3.5.2以上的代码生成器

MyBatisPlus最新的3.5.2以上的代码生成器。

apple_51927114的博客 730
上一篇: MybatisPlus(1)
下一篇: java查漏补缺(1)
anotherQu
博客等级 码龄6年 21粉丝 36原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值