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把生成根项目的文件拷贝到对应的工程下