Java31:MYBATIS-PLUS
一简介MyBatis-Plus (opens new window)简称 MP是一个 MyBatis (opens new window) 的增强工具在 MyBatis 的基础上只做增强不做改变为简化开发、提高效率而生。特性- 无侵入只做增强不做改变引入它不会对现有工程产生影响如丝般顺滑- 损耗小启动即会自动注入基本 CURD性能基本无损耗直接面向对象操作- 强大的 CRUD 操作内置通用 Mapper、通用 Service仅仅通过少量配置即可实现单表大部分 CRUD 操作更有强大的条件构造器满足各类使用需求- 支持 Lambda 形式调用通过 Lambda 表达式方便的编写各类查询条件无需再担心字段写错- 支持主键自动生成支持多达 4 种主键策略内含分布式唯一 ID 生成器 - Sequence可自由配置完美解决主键问题- 支持 ActiveRecord 模式支持 ActiveRecord 形式调用实体类只需继承 Model 类即可进行强大的 CRUD 操作- 支持自定义全局通用操作支持全局通用方法注入 Write once, use anywhere - 内置代码生成器采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码支持模板引擎更有超多自定义配置等您来使用- 内置分页插件基于 MyBatis 物理分页开发者无需关心具体操作配置好插件之后写分页等同于普通 List 查询mybatis-plus总结自动生成单表的CRUD功能提供丰富的条件拼接方式全自动ORM类型持久层框架二快速入门:步骤1创建工程并添加依赖dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-jdbc/artifactId /dependency dependency groupIdcom.alibaba/groupId artifactIddruid-spring-boot-3-starter/artifactId version1.2.20/version /dependency dependencygroupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version/dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.28/version /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId version1.18.28/version /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId /dependency /dependencies步骤2创建数据表及对应实体类package com.cn.mybatisplus.pojo; import jdk.jfr.DataAmount; import lombok.Data; Data public class Users { private Integer uid; private String uname; private String passwd; private String uemail; }步骤3创建mapper接口及yaml配置文件package com.cn.mybatisplus.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.cn.mybatisplus.pojo.Users; public interface UsersMapper extends BaseMapperUsers { }application.yamlspring: datasource: type: com.alibaba.druid.pool.DruidDataSource druid: username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/studb?useUnicodetruecharacterEncodingutf-8步骤4:创建启动类package com.cn.mybatisplus; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; MapperScan(com.cn.mybatisplus.mapper) SpringBootApplication public class Main { public static void main(String[] args) { SpringApplication.run(Main.class,args); } }步骤5创建测试类package com.cn.mybatisplus; import com.cn.mybatisplus.mapper.UsersMapper; import com.cn.mybatisplus.pojo.Users; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.List; SpringBootTest public class MybatisplusTest { Autowired private UsersMapper usersMapper; Test public void test(){ ListUsers users usersMapper.selectList(null); System.out.println(users users); } }三mybatis核心功能1.基于Mapper接口crud功能通用 CRUD 封装BaseMapper (opens new window)接口 Mybatis-Plus 启动时自动解析实体表关系映射转换为 Mybatis 内部对象注入容器! 内部包含常见的单表操作新增// 插入一条记录 // T 就是要插入的实体对象int insert(T entity);删除// 根据 entity 条件删除记录int delete(Param(Constants.WRAPPER) WrapperT wrapper);// 删除根据ID 批量删除int deleteBatchIds(Param(Constants.COLLECTION) Collection? extends Serializable idList);// 根据 ID 删除int deleteById(Serializable id);// 根据 columnMap 条件删除记录int deleteByMap(Param(Constants.COLUMN_MAP) MapString, Object columnMap);修改// 根据 whereWrapper 条件更新记录int update(Param(Constants.ENTITY) T updateEntity, Param(Constants.WRAPPER) Wrapper whereWrapper);// 根据 ID 修改 主键属性必须值int updateById(Param(Constants.ENTITY) T entity);// 根据 whereWrapper 条件更新记录int update(Param(Constants.ENTITY) T updateEntity, Param(Constants.WRAPPER) Wrapper whereWrapper);// 根据 ID 修改 主键属性必须值int updateById(Param(Constants.ENTITY) T entity);查询:// 根据 ID 查询T selectById(Serializable id);// 根据 entity 条件查询一条记录T selectOne(Param(Constants.WRAPPER) WrapperT queryWrapper);// 查询根据ID 批量查询ListT selectBatchIds(Param(Constants.COLLECTION) Collection? extends Serializable idList);测试步骤1:启动类mapper接口同上步骤2实体类package com.cn.mybatisplus.pojo; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; Data TableName(users) public class Users { TableId private Integer uid; private String uname; private String passwd; private String uemail; }步骤3appliation.yaml文件spring: datasource: type: com.alibaba.druid.pool.DruidDataSource druid: username: root password: root url: jdbc:mysql://localhost:3306/studb?useUnicodetruecharacterEncodingutf-8 driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl步骤4:测试类package com.cn.mybatisplus; import com.cn.mybatisplus.mapper.UsersMapper; import com.cn.mybatisplus.pojo.Users; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; SpringBootTest public class MybatisplusTest { Autowired private UsersMapper usersMapper; Test public void test_insert(){ Users u1 new Users(); u1.setUname(zhaoliu); u1.setPasswd(123123); u1.setUemail(zhaoliuqq.com); int rows usersMapper.insert(u1); System.out.println(rows rows); } Test public void test_update(){ Users u1 new Users(); u1.setUid(5); u1.setUname(zhaoliu6); u1.setPasswd(666666); int rows usersMapper.updateById(u1); System.out.println(rows rows); Users u2 new Users(); u2.setPasswd(7777777); int rows2 usersMapper.update(u2, null); System.out.println(rows2 rows2); } Test public void test_delete(){ int rows usersMapper.deleteById(5); System.out.println(rows rows); MapString,Object map new HashMap(); map.put(uname,wangwu); int delete usersMapper.deleteByMap(map); System.out.println(delete delete); } Test public void test_select (){ Users users usersMapper.selectById(1); System.out.println(users users); ListInteger ids new ArrayList(); ids.add(1); ids.add(2); ListUsers usersList usersMapper.selectBatchIds(ids); System.out.println(usersList usersList); } }2.基于Service层的crud功能通用 Service CRUD 封装[IService 接口进一步封装 CRUD 采用 get 查询单行 remove 删除 list 查询集合 page 分页 前缀命名方式区分 Mapper 层避免混淆对比Mapper接口CRUD区别- service添加了批量方法- service层的方法自动添加事务使用Iservice接口方式接口继承IService接口Javapublic interface UserService extends IServiceUser {}类继承ServiceImpl实现类JavaServicepublic class UserServiceImpl extends ServiceImplUserMapper,User implements UserService{}CRUD方法介绍Java保存// 插入一条记录选择字段策略插入boolean save(T entity);// 插入批量boolean saveBatch(CollectionT entityList);// 插入批量boolean saveBatch(CollectionT entityList, int batchSize);修改或者保存// TableId 注解存在更新记录否插入一条记录boolean saveOrUpdate(T entity);// 根据updateWrapper尝试更新否继续执行saveOrUpdate(T)方法boolean saveOrUpdate(T entity, WrapperT updateWrapper);// 批量修改插入boolean saveOrUpdateBatch(CollectionT entityList);// 批量修改插入boolean saveOrUpdateBatch(CollectionT entityList, int batchSize);移除// 根据 queryWrapper 设置的条件删除记录boolean remove(WrapperT queryWrapper);// 根据 ID 删除boolean removeById(Serializable id);// 根据 columnMap 条件删除记录boolean removeByMap(MapString, Object columnMap);// 删除根据ID 批量删除boolean removeByIds(Collection? extends Serializable idList);更新// 根据 UpdateWrapper 条件更新记录 需要设置sqlsetboolean update(WrapperT updateWrapper);// 根据 whereWrapper 条件更新记录boolean update(T updateEntity, WrapperT whereWrapper);// 根据 ID 选择修改boolean updateById(T entity);// 根据ID 批量更新boolean updateBatchById(CollectionT entityList);// 根据ID 批量更新boolean updateBatchById(CollectionT entityList, int batchSize);数量// 查询总记录数int count();// 根据 Wrapper 条件查询总记录数int count(WrapperT queryWrapper);查询// 根据 ID 查询T getById(Serializable id);// 根据 Wrapper查询一条记录。结果集如果是多个会抛出异常随机取一条加上限制条件 wrapper.last(LIMIT 1)T getOne(WrapperT queryWrapper);// 根据 Wrapper查询一条记录T getOne(WrapperT queryWrapper, boolean throwEx);// 根据 Wrapper查询一条记录MapString, Object getMap(WrapperT queryWrapper);// 根据 Wrapper查询一条记录V V getObj(WrapperT queryWrapper, Function? super Object, V mapper);集合// 查询所有ListT list();// 查询列表ListT list(WrapperT queryWrapper);// 查询根据ID 批量查询CollectionT listByIds(Collection? extends Serializable idList);// 查询根据 columnMap 条件CollectionT listByMap(MapString, Object columnMap);// 查询所有列表ListMapString, Object listMaps();// 查询列表ListMapString, Object listMaps(WrapperT queryWrapper);测试步骤1依赖启动类实体类application.yaml配置文件同上步骤2service层接口和实现类package com.cn.mybatisplus.service; import com.baomidou.mybatisplus.extension.service.IService; import com.cn.mybatisplus.pojo.Users; import org.springframework.stereotype.Service; Service public interface UsersService extends IServiceUsers { }package com.cn.mybatisplus.service; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.cn.mybatisplus.mapper.UsersMapper; import com.cn.mybatisplus.pojo.Users; import org.springframework.stereotype.Service; Service public class UsersServiceImpl extends ServiceImplUsersMapper, Users implements UsersService { }步骤3测试package com.cn.mybatisplus; import com.cn.mybatisplus.pojo.Users; import com.cn.mybatisplus.service.UsersService; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.ArrayList; import java.util.List; SpringBootTest public class MybatisplusServiceTest { Autowired private UsersService usersService; Test public void test_save(){ //单个保存 Users u1 new Users(); u1.setUname(qiaofeng); u1.setPasswd(abc123); u1.setUemail(qiaofengqq.com); boolean save usersService.save(u1); System.out.println(save save); //批量保存 Users u2 new Users(); u2.setUname(duanyu); u2.setPasswd(abc111); u2.setUemail(duanyuqq.com); Users u3 new Users(); u3.setUname(xuzhu); u3.setPasswd(abc666); u3.setUemail(xuzhuqq.com); ListUsers list new ArrayListUsers(); list.add(u2); list.add(u3); boolean saveBatch usersService.saveBatch(list); System.out.println(saveBatch saveBatch); } Test public void test_update(){ //按id修改 Users u1 new Users(); u1.setUid(-319627262); u1.setUname(qiaofeng22); u1.setPasswd(abc12322); u1.setUemail(qiaofeng22qq.com); boolean update usersService.updateById(u1); System.out.println(update update); } Test public void test_remove(){ // 按id删除 Users u1 new Users(); u1.setUid(-319627262); boolean remove usersService.removeById(u1); System.out.println(remove remove); } Test public void test_select(){ //按id查询 Users serviceById usersService.getById(2); System.out.println(serviceById serviceById); //查询全部 ListUsers list usersService.list(null); System.out.println(list list); } }3.分页插件查询使用步骤1在启动器类导入分页插件package com.cn.mybatisplus; 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.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; MapperScan(com.cn.mybatisplus.mapper) SpringBootApplication public class Main { public static void main(String[] args) { SpringApplication.run(Main.class,args); } Bean public MybatisPlusInterceptor plusInterceptor(){ //mybatisplus插件集合 MybatisPlusInterceptor mybatisPlusInterceptor new MybatisPlusInterceptor(); //添加分页插件 mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return mybatisPlusInterceptor; } }步骤2使用分页插件SpringBootTest public class MybatisplusServiceTest { Autowired private UsersService usersService; Test public void test_page(){ //设置分页参数第一个参数是第几页第二个参数是每页的个数 Page pagenew Page(1,3); Page page1 usersService.page(page, null); long pages page1.getPages(); System.out.println(总页数是 pages); long current page1.getCurrent(); System.out.println(当前页是 current); List records page1.getRecords(); System.out.println(当前页面的数据 records); long total page1.getTotal(); System.out.println(总记录数 total); }}4.自定义方法使用分页插件步骤1添加分页插件同上步骤2定义实体类package com.cn.mybatisplus.pojo; import lombok.Data; Data public class Students { private Integer id; private String name; private String gender; private Integer age; private String classes; }步骤3定义mapper接口package com.cn.mybatisplus.mapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.cn.mybatisplus.pojo.Students; import org.apache.ibatis.annotations.Param; public interface StudentsMapper { IPageStudents queryStduentByAge(IPageStudents page, Param(age) Integer age); }步骤4: 在resources根目录下创建目录mapper并定义StduentsMapper.xml?xml version1.0 encodingUTF-8 ? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN https://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.cn.mybatisplus.mapper.StudentsMapper select idqueryStduentByAge resultTypestudents select id,name,gender ,age, class as classes from students where age #{age} /select /mapper步骤5在application.yaml中添加别名配置spring: datasource: type: com.alibaba.druid.pool.DruidDataSource druid: username: root password: root url: jdbc:mysql://localhost:3306/studb?useUnicodetruecharacterEncodingutf-8 driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl type-aliases-package: com.cn.mybatisplus.pojo步骤6测试SpringBootTest public class MybatisplusTest { Autowired private StudentsMapper studentsMapper;Test public void test_page (){ //设置分页参数第一个参数是第几页第二个参数是每页的个数 Page pagenew Page(1,3); IPage page1 studentsMapper.queryStduentByAge(page, 30); long pages page1.getPages(); System.out.println(总页数是 pages); long current page1.getCurrent(); System.out.println(当前页是 current); List records page1.getRecords(); System.out.println(当前页面的数据 records); long total page1.getTotal(); System.out.println(总记录数 total); }}5.条件构造器使用1.定义使用MyBatis-Plus的条件构造器你可以构建灵活、高效的查询条件而不需要手动编写复杂的 SQL 语句。它提供了许多方法来支持各种条件操作符并且可以通过链式调用来组合多个条件。这样可以简化查询的编写过程并提高开发效率。Wrapper 条件构造抽象类最顶端父类- AbstractWrapper 用于查询条件封装生成 sql 的 where 条件- QueryWrapper 查询/删除条件封装- UpdateWrapper 修改条件封装- AbstractLambdaWrapper 使用Lambda 语法- LambdaQueryWrapper 用于Lambda语法使用的查询Wrapper- LambdaUpdateWrapper Lambda 更新封装Wrapper2.QueryWrapperTest public void test() { //条件拼接 QueryWrapperStudents queryWrapper new QueryWrapper(); queryWrapper.like(name, 三); queryWrapper.eq(gender, 男); queryWrapper.isNotNull(age); //链式调用 QueryWrapperUsers queryWrapper1 new QueryWrapper(); queryWrapper1.like(name, 六).eq(gender, 女).isNotNull(age); ListStudents studentsList studentsMapper.selectList(queryWrapper); System.out.println(studentsList studentsList); System.out.println(______________________); ListStudents studentsList1 studentsMapper.selectList(queryWrapper); System.out.println(studentsList1 studentsList1); }Test public void test2() { QueryWrapperStudents queryWrapper new QueryWrapper(); // or的使用和between queryWrapper.between(age,51,55); queryWrapper.or().eq(age,99); //添加排序 queryWrapper.orderByDesc(age).orderByAsc(id); //查询指定的列默认查询全部 queryWrapper.select(name,age); ListStudents studentsList studentsMapper.selectList(queryWrapper); System.out.println(studentsList studentsList); }Test public void test3() { //模拟前端传值 Integer age50; QueryWrapperStudents queryWrapper new QueryWrapper(); //加条件判断条件值为true拼接条件 queryWrapper.eq(age !null age18,age,age); ListStudents studentsList studentsMapper.selectList(queryWrapper); System.out.println(studentsList studentsList); }3.UpdateWrapperqueryWrapper 与UpdateWrapper 区别 Test public void test5() { QueryWrapperStudents queryWrapper new QueryWrapper(); queryWrapper.between(age,51,55); Students stu new Students(); stu.setAge(66); //QueryWrapper 不能修改值为null stu.setGender(null); int update studentsMapper.update(stu, queryWrapper); System.out.println(update update); System.out.println(_________________________); UpdateWrapperStudents updateWrapper new UpdateWrapper(); updateWrapper.between(age,51,55); //1.直接携带修改数据 set(列名,列值) //2.指定任意值修改 set(列名,null) updateWrapper.set(age,66); updateWrapper.set(classes,null); int update2 studentsMapper.update(null, updateWrapper); System.out.println(update2 update2); }4.LambdaQueryWrapperLambdaQueryWrapper 使用了实体类的属性引用例如 Students::getName、Students::getAge而不是字符串来表示字段名这提高了代码的可读性和可维护性。Test public void testLambdaQuerryWrapper() { LambdaQueryWrapperStudents lambdaQueryWrapper new LambdaQueryWrapper(); lambdaQueryWrapper.like(Students::getName,三); lambdaQueryWrapper.gt(Students::getAge,18); ListStudents studentsList studentsMapper.selectList(lambdaQueryWrapper); System.out.println(studentsList studentsList); }6.核心注解TableName注解描述表名注解标识实体类对应的表使用位置实体类TableName(sys_user) //对应数据库表名public class User {private Long id;private String name;private Integer age;private String email;}可以通过全局配置文件统一设置表的前缀mybatis-plus: # mybatis-plus的配置global-config:db-config:table-prefix: sys_ # 表名前缀字符串TableId 注解描述主键注解使用位置实体类主键字段TableName(sys_user)public class User {TableId(value主键列名,type主键策略)private Long id;private String name;private Integer age;private String email;}IdType属性可选值值描述AUTO数据库 ID 自增 (mysql配置主键自增长)ASSIGN_ID默认分配 ID(主键类型为 Number(Long )或 String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)TableField描述字段注解非主键TableName(sys_user)public class User {TableIdprivate Long id;TableField(nickname)private String name;private Integer age;private String email;}四核心扩展1.逻辑删除实现逻辑删除可以方便地实现对数据库记录的逻辑删除而不是物理删除。逻辑删除是指通过更改记录的状态或添加标记字段来模拟删除操作从而保留了删除前的数据便于后续的数据分析和恢复。步骤1数据库添加删除字段alter table users add deleted int default 0步骤2实体列添加删除属性并添加注解TableLogicData TableName(users) public class Users { TableId private Integer uid; private String uname; private String passwd; private String uemail; TableLogic private Integer deleted; }步骤3测试删除查看日志打印Test public void test_tablelogic (){ //UPDATE users SET deleted1 WHERE uid? AND deleted0 int deleteById usersMapper.deleteById(1); System.out.println(deleteById deleteById); //SELECT uid,uname,passwd,uemail,deleted FROM users WHERE deleted0 ListUsers usersList usersMapper.selectList(null); System.out.println(usersList usersList); }全局配置也可以实现逻辑删除mybatis-plus: configuration: global-config: db-config: logic-delete-field: deleted2.乐观锁实现悲观锁悲观锁的基本思想是在整个数据访问过程中将共享资源锁定以确保其他线程或进程不能同时访问和修改该资源。悲观锁的核心思想是先保护再修改。在悲观锁的应用中线程在访问共享资源之前会获取到锁并在整个操作过程中保持锁的状态阻塞其他线程的访问。只有当前线程完成操作后才会释放锁让其他线程继续操作资源。这种锁机制可以确保资源独占性和数据的一致性但是在高并发环境下悲观锁的效率相对较低。乐观锁乐观锁的基本思想是认为并发冲突的概率较低因此不需要提前加锁而是在数据更新阶段进行冲突检测和处理。乐观锁的核心思想是先修改后校验。在乐观锁的应用中线程在读取共享资源时不会加锁而是记录特定的版本信息。当线程准备更新资源时会先检查该资源的版本信息是否与之前读取的版本信息一致如果一致则执行更新操作否则说明有其他线程修改了该资源需要进行相应的冲突处理。乐观锁通过避免加锁操作提高了系统的并发性能和吞吐量但是在并发冲突较为频繁的情况下乐观锁会导致较多的冲突处理和重试操作。具体技术和方案:1. 乐观锁实现方案和技术- 版本号/时间戳为数据添加一个版本号或时间戳字段每次更新数据时比较当前版本号或时间戳与期望值是否一致若一致则更新成功否则表示数据已被修改需要进行冲突处理。- CASCompare-and-Swap使用原子操作比较当前值与旧值是否一致若一致则进行更新操作否则重新尝试。- 无锁数据结构采用无锁数据结构如无锁队列、无锁哈希表等通过使用原子操作实现并发安全。2. 悲观锁实现方案和技术- 锁机制使用传统的锁机制如互斥锁Mutex Lock或读写锁Read-Write Lock来保证对共享资源的独占访问。- 数据库锁在数据库层面使用行级锁或表级锁来控制并发访问。- 信号量Semaphore使用信号量来限制对资源的并发访问。实现步骤1. 添加版本号更新插件MapperScan(com.cn.mybatisplus.mapper) SpringBootApplication public class Main { public static void main(String[] args) { SpringApplication.run(Main.class,args); } Bean public MybatisPlusInterceptor plusInterceptor(){ //mybatisplus插件集合 MybatisPlusInterceptor mybatisPlusInterceptor new MybatisPlusInterceptor(); //添加分页插件 mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); //添加版本管理插件mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return mybatisPlusInterceptor; } }2.实体类添加version属性和注解Version private Integer version;3.数据库添加版本字段alter table users add version int default 14.测试Test public void test_table_lock (){ Users user1 usersMapper.selectById(2); Users user2 usersMapper.selectById(2); user1.setPasswd(111111); user2.setPasswd(222222); usersMapper.updateById(user1);//版本11更新成功更新版本为2 usersMapper.updateById(user2);//版本12更新失败 }五代码生成器1.逆向工程根据数据库表生成 sevice mapper mapper.xml 和实体类步骤1确认安装mybatsx插件步骤2idea 连接mysql数据库输入连接信息并点击测试连接步骤3:选择对应的表选择自动生成步骤4:选择工程和根路径步骤5:按截图选择对应内容,点击完成步骤6把生成根项目的文件拷贝到对应的工程下

相关新闻

【EU thetis_MRV网站之信息构成】

【EU thetis_MRV网站之信息构成】

信息类梳理(一) 目录 网站构成梳理(一) 前言 一、Ship 1. Ship Particulars 2. Owner 二、Company 1. MRV / ETS 三、Verifier 1. MRV / ETS 总结 前言 EU thetis_mrv网站中可以分为2大类: 信息类 Ship&a…

2026/7/21 19:46:45阅读更多 →
Fossilize完全指南:Vulkan对象序列化的终极解决方案

Fossilize完全指南:Vulkan对象序列化的终极解决方案

Fossilize完全指南:Vulkan对象序列化的终极解决方案 【免费下载链接】Fossilize A serialization format for various persistent Vulkan object types. 项目地址: https://gitcode.com/gh_mirrors/fo/Fossilize Fossilize是Vulkan图形API的终极序列化解决方…

2026/7/21 19:46:45阅读更多 →
为什么权重负载均衡中,不是“权重大就优先选”,而是通过“随机数 + 累计权重”的方式来选择实例?

为什么权重负载均衡中,不是“权重大就优先选”,而是通过“随机数 + 累计权重”的方式来选择实例?

引言 在微服务架构中,负载均衡是保障系统高可用性和性能的核心技术之一。常见的权重负载均衡(Weighted Load Balancing)策略中,开发者常会疑惑:为什么不是“权重大就优先选”,而是通过“随机数 累计权重”…

2026/7/21 19:46:45阅读更多 →
YOLOv13改进策略【Conv和Transformer】| CVPR2025 CATANet LRSA局部区域自注意力 重叠分块交互 + 共享多头权重,精细复原图像纹理细节

YOLOv13改进策略【Conv和Transformer】| CVPR2025 CATANet LRSA局部区域自注意力 重叠分块交互 + 共享多头权重,精细复原图像纹理细节

一、本文介绍 本文记录的是利用LRSA局部区域自注意力优化YOLOv13的目标检测网络模型。 LRSA(Local-Region Self-Attention)通过重叠滑动窗口分块、全局共享多头注意力与通道卷积增强结合,实现图像邻域像素精细上下文交互,弥补长程聚合模块缺失的局部纹理信息。本文利用LR…

2026/7/21 23:47:12阅读更多 →
HarmonyOS应用开发实战:萌宠日记 - 回调函数模式

HarmonyOS应用开发实战:萌宠日记 - 回调函数模式

前言 在 萌宠日记 中,页面间数据传递 是一个核心需求。当用户在 首页 点击“宠物档案“时,需要通知 Index 父组件 执行 NavPathStack.pushPath 跳转到子页面。这种 子 → 父 的通信方式,我们采用了 回调函数模式 — 父组件通过属性传入 lamb…

2026/7/21 23:47:12阅读更多 →
深圳购房必看:得房率如何影响房价与居住体验

深圳购房必看:得房率如何影响房价与居住体验

1. 得房率概念解析:买房必须懂的核心指标得房率这个专业术语,对于首次置业的刚需群体来说可能有些陌生,但它直接关系到你花几百万买的房子实际能使用的面积有多少。简单来说,得房率就是套内使用面积与建筑面积的比值。举个例子&am…

2026/7/21 23:47:12阅读更多 →
Godot动画系统全解析:从AnimationPlayer到AnimationTree实战指南

Godot动画系统全解析:从AnimationPlayer到AnimationTree实战指南

1. 项目概述:为什么Godot的动画系统值得你投入时间?如果你刚开始接触Godot引擎,可能会觉得它的动画系统有点“另类”。不像Unity的Animator Controller那样用状态机连线,也不像Cocos Creator那样依赖编辑器动画剪辑,Go…

2026/7/21 23:47:12阅读更多 →
工业防爆监控选型技术指南:山西煤炭化工场景适配方案解析

工业防爆监控选型技术指南:山西煤炭化工场景适配方案解析

摘要山西煤炭、煤化工、矿山等危险环境对防爆视频监控的防爆性能、环境耐受度、智能识别能力要求严苛。本文从防爆国标、硬件结构、环境适配、软件算法、工程配套服务五大维度,拆解防爆监控选型技术标准,结合成熟工业设备完成场景适配分析,为…

2026/7/21 23:47:12阅读更多 →
CocosCreator PageView深度调优:从原理到实战解决卡顿与误触

CocosCreator PageView深度调优:从原理到实战解决卡顿与误触

1. 项目概述:从“能用”到“好用”的必经之路在CocosCreator项目里,PageView(翻页视图)组件几乎是实现引导页、商城轮播、关卡选择这类横向滑动界面的首选。很多开发者,包括我自己在早期项目里,都是从官方文…

2026/7/21 23:45:12阅读更多 →
Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/21 0:51:49阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/21 0:51:49阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/21 0:51:49阅读更多 →
Windows+macOS 通用 OpenClaw 部署流程,内置依赖一键启动智能桌面助手

Windows+macOS 通用 OpenClaw 部署流程,内置依赖一键启动智能桌面助手

📌教程适配:OpenClaw v2.7.9 | 兼容 Windows10/11、macOS 双系统 📖前言 当下各类本地 AI 工具层出不穷,多数产品仅能完成文字问答交互,很难直接操控电脑执行实际操作。OpenClaw,业内常称小龙虾 AI&#…

2026/7/21 0:01:46阅读更多 →
Codex 接入后 Bug 反增?复盘从个人演示到团队协作的“流程陷阱”

Codex 接入后 Bug 反增?复盘从个人演示到团队协作的“流程陷阱”

聊《一次Codex项目复盘,问题最后出在流程而不是模型》之前,先说一句实在的:别急着背概念,先看它在真实项目里到底解决什么问题。摘要先把这篇文章的目标说清楚:看完之后,你应该能判断这件事值不值得做&…

2026/7/21 0:01:46阅读更多 →
手把手搓一个五子棋游戏,零代码也能当“游戏开发者”

手把手搓一个五子棋游戏,零代码也能当“游戏开发者”

大家好,还是我。前几期带大家做了心情日记本和可视化大屏,后台有朋友留言:“能不能教点好玩的?我想做游戏,但一行代码都不会。”行,这期就安排。今天的目标:从零做一个五子棋游戏。 带AI对战、三…

2026/7/21 0:03:46阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/21 22:53:50阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/21 18:53:30阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/21 18:53:30阅读更多 →