MyBatisPlus笔记

MP入门

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

Mybatis-Plus已经封装好了大量增删改查的方法,程序员只需要继承BaseMapper就可以使用这些方法了,无需自己再开发。

案例实现

向数据库保存一个User对象

创建数据表

sql 复制代码
create table tb_user (
         id bigint(20) primary key auto_increment,
         username varchar(30) unique not null,
         name varchar(30) not null,
         password varchar(32) not null,
         age int(3) not null ,
         tel varchar(32) not null,
         create_time datetime,
         update_time datetime
);
insert into tb_user values(1,'zhangsan1','tom','123456',12,'12345678911',now(),now());
insert into tb_user values(2,'zhangsan2','jack','123456',8,'12345678912',now(),now());
insert into tb_user values(3,'zhangsan3','jerry','123456',15,'12345678910',now(),now());
insert into tb_user values(4,'zhangsan4','tom','123456',9,'12345678910',now(),now());
insert into tb_user values(5,'zhangsan5','snake','123456',28,'12345678910',now(),now());
insert into tb_user values(6,'zhangsan6','张益达','123456',22,'12345678910',now(),now());
insert into tb_user values(7,'zhangsan7','张大炮','123456',16,'12345678910',now(),now());

创建工程

xml 复制代码
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.3</version>
    </parent>

    <dependencies>
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.3</version>
        </dependency>
        <!--mybatis plus依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>
        <!--lombok简化对象书写-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--hutool工具包-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.20</version>
        </dependency>
        <!--整合测试-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <!--web环境依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

创建实体类

java 复制代码
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Long id;
    private String username;
    private String name;
    private String password;
    private Integer age;
    private String tel;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
}

创建接口

自定义的Mapper接口需要实现BaseMapper<实体类>,然后就可以继承到BaseMapper中定义的方法了

java 复制代码
@Mapper
public interface UserMapper extends BaseMapper<User> {
    
    //声明方法+注解实现sql
    
}

添加配置文件

在resources中添加配置文件application.yml,然后在里面加入下面配置

yaml 复制代码
spring:
 datasource:
   driver-class-name: com.mysql.cj.jdbc.Driver
   url: jdbc:mysql://localhost:3306/mp
   username: root
   password: 123456
   # druid 阿里    HkariCp(springBoot)
   type: com.alibaba.druid.pool.DruidDataSource

mybatis-plus:
 configuration:
   log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 日志打印
   map-underscore-to-camel-case: true # 驼峰映射

创建启动类

java 复制代码
@SpringBootApplication
public class MpApplication {
    public static void main(String[] args) {
        SpringApplication.run(MpApplication.class,args);
    }
}

测试

java 复制代码
@SpringBootTest
public class UserMapperTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void testInsert() {
        //1. 封装user对象
        User user = User.builder()
                .username("lisi1")
                .name("tom")
                .password("123456")
                .age(18)
                .tel("13700137001")
                .build();
        //2. 调用mapper方法
        userMapper.insert(user);
    }
}

案例细节

@TableName

标注在实体类上,用于声明实体类对应的表,如果表名和类名一致可以省略

java 复制代码
//标注在实体类上,用于声明实体类对应的表,如果表名和类名一致可以省略
@TableName("tb_user")
public class User {
    ....
}

如果大部分表都是以固定前缀开头,可以全局配置表前缀,但优先级比注解配置低

yaml 复制代码
mybatis-plus:
  global-config:
    db-config:
      table-prefix: tb_ #表前缀

@TableId

标注在主键字段上,用于声明主键生成策略

java 复制代码
    //主键生成策略
    //AUTO : 数据库的自增
    //INPUT: 让用户自己输入主键
    //ASSIGN_ID: 雪花算法生成的一个纯数字
    //ASSIGN_UUID: UUID生成一个不重复字符串
    //ASSIGN_NONE: INPUT+ASSIGN_ID
    @TableId(type = IdType.AUTO)
    private Long id;
描述
AUTO 数据库主键自增
INPUT 手动设置主键值
ASSIGN_ID 由雪花算法生成的纯数字
ASSIGN_UUID UUID生成的字符串
NONE 默认值相当于INPUT+ASSIGN_ID

如果大部分表主键都是自增,可以进行全局设置,但优先级比注解配置低

yaml 复制代码
mybatis-plus:
  global-config:
    db-config:
      id-type: auto #主键策略
      table-prefix: tbl_ #表前缀

Mapper接口

BaseMapper:通用 CRUD 接口,内部声明了大量的单表操作方法,泛型 T 为任意实体对象

java 复制代码
@Mapper
public interface ProductMapper extends BaseMapper<Product> {

}

基本使用

MybatisPlus提供了单表的增删改查方法,常用的如下

java 复制代码
// 插入一条记录
int insert(T entity);

// 主键查询
T selectById(Serializable id);
// 主键批量查询
List<T> selectBatchIds(Collection idList); 

// 根据ID修改不为空的字段
int updateById(T entity);

// 根据ID删除
int deleteById(Serializable id);

// 根据ID集合批量删除
int deleteBatchIds(Collection idList);
java 复制代码
@SpringBootTest
public class UserMapperTest {

    @Autowired
    private UserMapper userMapper;

    //插入一条记录
    //int insert(T entity);
    @Test
    public void testInsert() {
        //1. 封装user对象
        User user = User.builder()
                .username("lisi1")
                .name("tom")
                .password("123456")
                .age(18)
                .tel("13700137001")
                .build();
        //2. 调用mapper方法
        userMapper.insert(user);
    }


    //主键查询
    //T selectById(Serializable id);
    @Test
    public void testSelectById() {
        User user = userMapper.selectById(1L);
        System.out.println(user);
    }

    //主键批量查询
    //List<T> selectBatchIds(Collection idList);
    @Test
    public void testSelectBatchIds() {
        //1. 构建id集合
        List<Long> idList = ListUtil.of(1L, 2L, 3L);
        //2. 执行查询
        List<User> userList = userMapper.selectBatchIds(idList);
        System.out.println(userList);
    }

    //根据ID修改不为空的字段
    //int updateById(T entity);
    @Test
    public void testUpdateById() {
        //1. 封装user对象
        User user = User.builder()
                .username("lisi2")
                .name("tom2")
                .tel("13700137002")
                .id(2L)//不要忘记设置id
                .build();
        userMapper.updateById(user);
    }

    //根据ID删除
    //int deleteById(Serializable id);
    @Test
    public void testDeleteById() {
        userMapper.deleteById(7L);
    }

    //根据ID集合批量删除
    //int deleteBatchIds(Collection idList);
    @Test
    public void testDeleteBatchIds() {
        List<Long> idList = ListUtil.of(1L, 2L, 3L);
        userMapper.deleteBatchIds(idList);
    }
}

条件查询

MybatisPlus提供了Wrapper对象来封装各种条件,比如条件、分页、排序、分组、过滤等等

java 复制代码
// 条件查询,当查询结果最多为一条记录时使用  手机号 身份证号  用户名  唯一约束
T selectOne(Wrapper<T> queryWrapper);

// 条件查询,当查询结果可能为多条记录时使用
List<T> selectList(Wrapper<T> queryWrapper);

书写格式

MybatisPlus支持使用多种格式组装条件,我们推荐使用Lambda格式

java 复制代码
@SpringBootTest
public class UserMapperTest2 {

    @Autowired
    private UserMapper userMapper;

    //根据name=李四和age>18查询(支持动态sql)
    @Test
    public void testSelectList1() {
        //0. 模仿前端传入参数
        String name = null;
        Integer age = 18;

        //1. 构建查询条件
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        if (StrUtil.isNotEmpty(name)) {
            wrapper.eq("name", name); //where name = '李四'
        }
        if (age != null) {
            wrapper.gt("age", age);//and age > 18
        }

        //2. 查询
        List<User> userList = userMapper.selectList(wrapper);

        userList.forEach(System.out::println);
    }

    //Lambda 根据name=李四和age>18查询(支持动态sql)
    @Test
    public void testSelectList2() {
        //0. 模仿前端传入参数
        String name = "李四";
        Integer age = 18;

        //1. 构建查询条件
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        //参数1位置是一个boolean值,只有这个值为true,当前条件才会生效
        wrapper.eq(StrUtil.isNotEmpty(name), User::getName, name);//where name = '李四'
        wrapper.gt(age != null, User::getAge, age);//and age > 18

        //2. 查询
        List<User> userList = userMapper.selectList(wrapper);

        userList.forEach(System.out::println);
    }

    //Lambda链式 根据name=李四和age>18查询(支持动态sql)
    @Test
    public void testSelectList3() {
        //0. 模仿前端传入参数
        String name = "李四";
        Integer age = 18;

        //1. 构建查询条件
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        //参数1位置是一个boolean值,只有这个值为true,当前条件才会生效
        wrapper.eq(StrUtil.isNotEmpty(name), User::getName, name)//where name = '李四'
                .gt(age != null, User::getAge, age);//and age > 18

        //2. 查询
        List<User> userList = userMapper.selectList(wrapper);

        userList.forEach(System.out::println);
    }
}

查询条件

查询方法 说明 例子
eq、ne、gt、ge、lt、le、isNull、isNotNull 比较运算 eq("name", "老王")--->name = '老王'
like、notLike、likeLeft、likeRight 模糊查询 likeRight("name", "王")--->name like '王%'
in、notIn、between、notBetween 范围运算 in("age",{1,2,3})--->age in (1,2,3)
or、and 拼接 eq("id",1).or().eq("name","老王")--->id = 1 or name = '老王'
java 复制代码
    //select * from tb_user where
    //id >= 1
    //and username = 'baima'
    //and name like '%四'
    //and age between 10 and 30
    //or tel in ('1370013001','1370013002')
    @Test
    public void testSelectList4() {
        //0. 模仿前端传入参数
        String name = "李四";
        Integer age = 18;

        //1. 构建查询条件
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.ge(User::getId,1)
                .eq(User::getUsername,"lisi")
                .likeLeft(User::getName,'四')
                .between(User::getAge,10,30)
                .or()
                .in(User::getTel,List.of("1370013001","1370013002"));

        //2. 查询
        List<User> userList = userMapper.selectList(wrapper);

        userList.forEach(System.out::println);
    }

其他条件

除了设置查询条件外,MP还支持:投影、排序、分组、过滤等功能

查询方法 说明 例子
select 投影 select("name","password")--->select name,password from 表
orderByAsc、orderByDesc 排序 orderByDesc("id", "name")--->order by id DESC,name DESC
groupBy 分组 groupBy("id", "name")--->group by id,name
having 过滤 having("sum(age) > 10")--->having sum(age) > 10
java 复制代码
@SpringBootTest
public class UserMapperTest2 {

    @Autowired
    private UserMapper userMapper;

    //投影和排序
    //select name,age from tb_user where id > 1 order by age desc
    @Test
    public void testSelectList1() {
        //1. 构建查询条件
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.gt(User::getId,1);//id > 1
        wrapper.select(User::getName,User::getAge);//select name,age
        wrapper.orderByDesc(User::getAge);//order by age desc
        wrapper.orderByAsc(User::getId);//order by id asc

        //2. 查询
        List<User> userList = userMapper.selectList(wrapper);

        userList.forEach(System.out::println);
    }


    //分组和过滤
    //select age,count(*) from tb_user group by age having count(*) >= 2
    @Test
    public void testSelectList2() {
        //1. 构建查询条件(LambdaQueryWrapper不支持分组和过滤)
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.select("age","count(*)");//select age,count(*)
        wrapper.groupBy("age");//group by age
        wrapper.having("count(*) >= 2");//having count(*) >= 2

        //2. 查询
        List<Map<String, Object>> list = userMapper.selectMaps(wrapper);

        list.forEach(System.out::println);
    }

    //分组和过滤
    //select age,count(*) from tb_user group by age having count(*) >= 2
    @Test
    public void testSelectList3() {
        List<Map<String, Object>> list = userMapper.count1();
        list.forEach(System.out::println);
    }

    @Test
    public void testSelectList4() {
        List<Re> list = userMapper.count2();
        list.forEach(System.out::println);
    }
}

UserMapper

java 复制代码
//自定义的Mapper 要求继承BaseMapper<实体类类型>
@Mapper
public interface UserMapper extends BaseMapper<User> {

    //自定义
    @Select("select age,count(*) from tb_user group by age having count(*) >= 2")
    List<Map<String, Object>> count1();

    @Select("select age,count(*) as num from tb_user group by age having num >= 2")
    List<Re> count2();
}

Re

java 复制代码
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Re {
    private String age;
    private Integer num;
}

分页查询

MybatisPlus内置了专门用于分页的插件,使用起来非常简单,它是基于拦截器原理实现分页的

① 配置拦截器

java 复制代码
@Configuration
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        //1 创建MybatisPlusInterceptor拦截器对象
        MybatisPlusInterceptor mpInterceptor=new MybatisPlusInterceptor();
        //2 添加分页拦截器
        mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return mpInterceptor;
    }
}

② 分页代码实现

java 复制代码
    //分页查询
    //select * from tb_user where id > 1 limit 5,7
    @Test
    public void testPage() {
        //1. 设置分页条件 当前页面 每页条数
        Page<User> page = new Page<>(2, 3);

        //2. 设置业务条件
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getAge, 18);

        //3. 调用分页方法
        page = userMapper.selectPage(page, wrapper);

        //4. 获取分页结果
        System.out.println("总条数:" + page.getTotal());
        System.out.println("总页数:" + page.getPages());
        System.out.println("当前页数据集合:" + page.getRecords());
    }

条件修改

java 复制代码
// 参数1: 封装要修改的字段  参数2: 封装更新条件
int update(T entity,Wrapper<T> updateWrapper);
java 复制代码
@SpringBootTest
public class UserMapperTest4 {

    @Autowired
    private UserMapper userMapper;

    //条件更新
    //update tb_user set age = 10,password = '123123' where name = 'tom'
    @Test
    public void testUpdate() {
        //1. 设置更新条件
        LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(User::getName, "tom");

        //2. 设置更新字段
        User user = User.builder()
                .age(10)
                .password("123123")
                .build();

        //3. 执行更新
        userMapper.update(user, wrapper);
    }
}

条件删除

java 复制代码
// 条件删除
int delete(Wrapper<T> wrapper);
java 复制代码
    //条件删除
    //delete from tb_user where name = 'tom';
    @Test
    public void testDelete() {
        //1. 设置删除条件
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getName, "tom");

        //2. 执行删除
        userMapper.delete(wrapper);
    }

实用功能

逻辑删除

逻辑删除指的是:当执行删除操作时,并不是将对应记录真正从数据库删掉,而是使用一个标识列,将要删除的数据标识为删除状态

MP使用@TableLogic就可以轻松实现这个功能

①:在user表中添加逻辑删除标记字段,并设置默认值为0

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

java 复制代码
    //逻辑删除字段:value用于指定未删除状态的值, delval用于指定删除状态的值
    @TableLogic(value = "0", delval = "1")
    private Integer deleted;

③ 删除其中一个用户观察效果

@TableLogic 只是单个表设置逻辑删除字段,如果多张表都需要配置逻辑删除,则可以做全局配置

yaml 复制代码
mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: deleted # 全局逻辑删除的实体字段名
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

自动填充

对于数据表中的一些公共字段,我们可以使用mybatisplus的自动填充功能来统一设置值

@TableField注解的fill属性可以完成这个功能 [1. 什么时候填充 2. 填充什么值]

① 在实体类的字段上添加注解

java 复制代码
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;

@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
描述
INSERT 插入时填充字段
UPDATE 更新时填充字段
INSERT_UPDATE 插入和更新时填充字段

② 在配置类中设置要填充的值

java 复制代码
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    //新增时执行此方法
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill ....");
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, "updateTime",  LocalDateTime.class, LocalDateTime.now());
    }

    //修改时执行此方法
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill ....");
        this.strictUpdateFill(metaObject, "updateTime",  LocalDateTime.class, LocalDateTime.now()); 
    }
}

③ 测试

java 复制代码
    //自动填充
    @Test
    public void testFill(){
        //1. 封装user对象
        User user = User.builder()
                .username("lisi10")
                .name("tom10")
                .password("123456")
                .age(18)
                .tel("13700137001")
                .build();
        //2. 调用mapper方法
        userMapper.insert(user);
    }

多余属性

多余属性指的是:实体类中存在,但是在数据表没有对应字段的属性

此时需要使用@TableField(exist = false)标识此属性

java 复制代码
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
//标注在实体类上,用于声明实体类对应的表,如果表名和类名一致可以省略
//@TableName("tb_user")
public class User {

    //type: 声明主键生成策略
    @TableId(type = IdType.AUTO)
    private Long id;
    private String username;
    private String name;
    private String password;

    @TableField(exist = false)//表示当前属性仅在实体类中存在,在数据表中没有对应的字段
    private String password2;

    private Integer age;
    private String tel;

    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;


    //逻辑删除字段:value用于指定未删除状态的值, delval用于指定删除状态的值
    //@TableLogic(value = "1", delval = "0")
    private Integer deleted;
}

ID精度损失问题

后端返回一个Long的id时候,前端接收到的数据精度有损失

pom.xml

xml 复制代码
        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
            <version>2.13.0</version>
        </dependency>

WebMvcConfig

java 复制代码
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    //扩展mvc框架的消息转换器
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        //创建消息转换器对象
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        //设置对象转换器,底层使用Jackson将Java对象转为json
        messageConverter.setObjectMapper(new JacksonObjectMapper());
        //将上面的消息转换器对象追加到mvc框架的转换器集合中
        converters.add(0, messageConverter);
    }
    
    /**
     * 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象
     * 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
     * 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
     */
    public class JacksonObjectMapper extends ObjectMapper {
        public JacksonObjectMapper() {
            super();

            //对应JDK8+ 时间类型处理需要添加的模块
            this.registerModule(new JavaTimeModule());

            //收到未知属性时不报异常
            this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);

            //反序列化时,属性不存在的兼容处理
            this.getDeserializationConfig().withoutFeatures(FAIL_ON_UNKNOWN_PROPERTIES);

            //自定义转换规则
            SimpleModule simpleModule = new SimpleModule()
                    .addSerializer(BigInteger.class, ToStringSerializer.instance)//将BigInteger转换为String
                    .addSerializer(Long.class, ToStringSerializer.instance);//将Long转换成String
            this.registerModule(simpleModule);
        }
    }
}

Service接口

介绍

为了简化service代码编写,mybatisPlus也提供了的基础接口和实现类

我们只需要让我们自己的service去继承它提供的service,就可以使用里面的方法

进一步封装 CRUD 采用 get 查询单行 remove 删除 list 查询集合 page 分页 前缀命名方式区分 Mapper 层避免混淆

分类 方法 描述
新增 boolean save(T entity) 新增,entity 实体对象
新增 boolean saveOrUpdate(T entity) id存在则更新记录,否插入一条记录
新增 boolean saveBatch(Collection entityList) 插入(批量),默认一次可以保存1000条数据
修改 boolean updateById(T entity) 根据 ID 修改
修改 boolean update(T entity,Wrapper updateWrapper) 根据 条件 修改
查询 T getById(Serializable id) 根据 ID 查询
查询 List listByIds(Collection idList) 查询(根据ID 批量查询)
查询 List list() 查询所有
查询 List list(Wrapper queryWrapper) 条件查询
删除 boolean removeById(Serializable id) 根据 ID 删除
删除 boolean removeByIds(Collection idList) 删除(根据ID 批量删除)
删除 boolean remove(Wrapper queryWrapper) 根据条件删除

修改Service

使用Service 接口使用

  • 接口继承 IService
  • 实现类继承 ServiceImpl<M,T>

UserService

java 复制代码
//自定义service接口
public interface UserService extends IService<User> {

}

UserServiceImpl

java 复制代码
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

}

修改controller

java 复制代码
@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/user")
    public Result findList(){
        List<User> userList = userService.list();
        return Result.success(userList);
    }

    @PostMapping("/user")
    public Result save(@RequestBody User user){
        userService.saveOrUpdate(user);
        return Result.success();
    }

    @DeleteMapping("/user/{id}")
    public Result deleteById(@PathVariable("id") Long id){
        userService.removeById(id);
        return Result.success();
    }

    @GetMapping("/user/{id}")
    public Result findById(@PathVariable("id") Long id){
        User user = userService.getById(id);
        return Result.success(user);
    }

    @PutMapping("/user")
    public Result update(@RequestBody User user){
        userService.saveOrUpdate(user);
        return Result.success();
    }
}

代码生成器

多表查询

相关推荐
C吴新科1 小时前
MySQL入门操作详解
mysql
Ai 编码助手3 小时前
MySQL中distinct与group by之间的性能进行比较
数据库·mysql
白云如幻4 小时前
MySQL排序查询
数据库·mysql
苹果醋34 小时前
Java8->Java19的初步探索
java·运维·spring boot·mysql·nginx
stars_User5 小时前
MySQL数据库面试题(下)
数据库·mysql
Yaml45 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
yanwushu5 小时前
Xserver v1.4.2发布,支持自动重载 nginx 配置
mysql·nginx·php·个人开发·composer
蓝眸少年CY6 小时前
MySQL 【流程控制】函数
mysql
掘金-我是哪吒7 小时前
微服务mysql,redis,elasticsearch, kibana,cassandra,mongodb, kafka
redis·mysql·mongodb·elasticsearch·微服务
zmgst8 小时前
canal1.1.7使用canal-adapter进行mysql同步数据
java·数据库·mysql