数据持久层框架:MyBatis-Plus
- 前言
- 注解
- 代码生成器
- CURD接口
- Service CRUD 接口
- Mapper CRUD 接口
- 条件构造器
- QueryWrapper和UpdateWrapper
- allEq
- eq、ne
- gt、ge、lt、le
- between、notBetween
- like、notLike、likeLeft、likeRight、notLikeLeft、notLikeRight
- isNull、isNotNull
- in、notIn、inSql、notInSql
- groupBy、orderByAsc、orderByDesc、having
- or、and
- exists、notExists
- 组合查询
- 动态条件查询
- 主键策略
- 逻辑删除
- 自动填充功能
- 防全表更新与删除插件
- MybatisX快速开发插件
前言
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 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 查询
- 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
- 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
- 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
以SpringBoot为例,导入依赖:
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.5</version>
</dependency>
数据库配置如下
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/spring_data?characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
示例代码如下:
@TableName("user")
public class User {private Integer id;private String name;private String age;//getter and setter
}
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
@SpringBootApplication
@MapperScan("com.example.mybatisstudy.dao")//扫描mapper
public class MybatisStudyApplication {public static void main(String[] args) {SpringApplication.run(MybatisStudyApplication.class, args);}}
@RunWith(SpringRunner.class)
@SpringBootTest
public class Test {@Autowiredprivate UserMapper userMapper;@org.junit.Testpublic void testSelect() {System.out.println(("----- selectAll method test ------"));List<User> userList = userMapper.selectList(null);userList.forEach(System.out::println);}
}
效果如图
从以上步骤中,我们可以看到集成MyBatis-Plus非常的简单,只需要引入 starter 工程,并配置 mapper 扫描路径即可。甚至连 XML 文件都不用编写!
注解
@TableName
:表名注解,标识实体类对应的表
@TableName("user")
public class User {private Integer id;private String name;private String age;//getter and setter
}
注解更多属性如图:
@TableId
:主键注解
@TableName("user")
public class User {@TableId(value = "id",type = IdType.AUTO)private Integer id;
}
types
属性指定主键类型,默认IdType.NONE
。
@TableField
:字段注解(非主键)
@TableName("user")
public class User {@TableId(value = "id",type = IdType.AUTO)private Integer id;@TableField(value = "name")private String name;
}
注解更多属性如图:
@Version
:乐观锁注解、标记在字段上。
@TableName("user")
public class User {@TableId(value = "id",type = IdType.AUTO)@Versionprivate Integer id;
}
然后注册Bean
@Configuration
public class MyConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return mybatisPlusInterceptor;}
}
@EnumValue
:普通枚举类注解。
@TableName("user")
public class User {@TableId(value = "id",type = IdType.AUTO)@Versionprivate Integer id;@EnumValueprivate String type;
}
@TableLogic
:表字段逻辑处理注解(逻辑删除)。
@TableName("user")
public class User {@TableId(value = "id",type = IdType.AUTO)private Integer id;@TableField(value = "name")@TableLogic(value = "a",delval = "b")private String name;
}
value
属性表示逻辑未删除值,delval
属性表示逻辑删除值。
@KeySequence
:于指定插入操作返回自增主键值的注解。在 MyBatis 中,有些数据库(如 Oracle)并不是像 MySQL 那样具有自增长主键的功能,而是通过序列(sequence)来生成主键值。
@TableName("user")
@KeySequence(value = "id",dbType = DbType.MYSQL)
public class User {
}
@InterceptorIgnore
:用于指定是否在某个方法上忽略拦截器的注解。
@Intercepts({@Signature(type= Executor.class,method = "update",args = {MappedStatement.class,Object.class})
})
public class ExampleInterceptor implements Interceptor {// 实现拦截器的逻辑// ...
}public interface UserMapper {@InterceptorIgnore@Insert("INSERT INTO users (id, name) VALUES (#{id}, #{name})")int insertUser(User user);}
@OrderBy
:指定查询操作的结果集的排序规则。
@TableName("user")
public class User {@TableId(value = "id", type = IdType.AUTO)private Integer id;@TableField(value = "name")private String name;@OrderBy(asc = true)private String age;
}
代码生成器
引入依赖
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.5.5</version></dependency><dependency><groupId>org.apache.velocity</groupId><artifactId>velocity-engine-core</artifactId><version>2.0</version></dependency>
示例代码如下:
public class Test {public static void main(String[] args) {FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/spring_data", "root", "123456")// 全局配置.globalConfig((scanner, builder) -> {builder.author(scanner.apply("请输入作者名称?"));// 获取用户的当前工作目录String userDir = System.getProperty("user.dir");builder.outputDir(userDir+"\\src\\main\\java\\"); // 指定输出目录})// 包配置.packageConfig((scanner, builder) -> builder.parent(scanner.apply("请输入包名?")))// 策略配置.strategyConfig((scanner, builder) -> builder.addInclude(getTables(scanner.apply("请输入表名,多个英文逗号分隔?所有输入 all"))).controllerBuilder().enableRestStyle().enableHyphenStyle().entityBuilder().enableLombok().addTableFills(new Column("create_time", FieldFill.INSERT)).build())/*模板引擎配置,默认 Velocity 可选模板引擎 Beetl 或 Freemarker.templateEngine(new BeetlTemplateEngine()).templateEngine(new FreemarkerTemplateEngine())*/.execute();}// 处理 all 情况protected static List<String> getTables(String tables){return "all".equals(tables) ? Collections.emptyList() : Arrays.asList(tables.split(","));}}
改进后,会自动生成到当前项目中,如图所示
CURD接口
Service CRUD 接口
Service CRUD 封装IService (opens new window)接口,进一步封装 CRUD 采用 get
查询单行 remove
删除 list
查询集合 page
分页 前缀命名方式区分 Mapper 层避免混淆,
public interface IUserService extends IService<User> {
}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
}
- Save
数据插入,如果数据已存在则报错
// 插入一条记录(选择字段,策略插入)
boolean save(T entity);
// 插入(批量)
boolean saveBatch(Collection<T> entityList);
// 插入(批量),batchSize:插入批次数量
boolean saveBatch(Collection<T> entityList, int batchSize);
示例代码如下:
@Controller
public class MyController {@Autowiredprivate IUserService iUserService;@GetMapping("/get")public void get(HttpServletResponse response){User user = new User();user.setId(9);user.setName("f");user.setAge("23");boolean b = iUserService.save(user);System.out.println(b);/** Output* true*/}
}
- SaveOrUpdate
先查询,数据库存在则更新记录,否插入一条记录
// TableId 注解存在更新记录,否插入一条记录
boolean saveOrUpdate(T entity);
// 根据updateWrapper尝试更新(类似条件)
boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper);
// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList);
// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);
示例代码如下:
@Controller
public class MyController {@Autowiredprivate IUserService iUserService;@GetMapping("/get")public void get(HttpServletResponse response){User user = new User();user.setId(6);user.setName("f");user.setAge("23");boolean b = iUserService.saveOrUpdate(user);User user2 = new User();user2.setId(8);user2.setName("g");user2.setAge("23");boolean b2 = iUserService.saveOrUpdate(user2);}
}
如图所示:
- Remove
数据删除
// 根据 queryWrapper 设置的条件,删除记录
boolean remove(Wrapper<T> queryWrapper);
// 根据 ID 删除
boolean removeById(Serializable id);
// 根据 columnMap 条件,删除记录
boolean removeByMap(Map<String, Object> columnMap);
// 删除(根据ID 批量删除)
boolean removeByIds(Collection<? extends Serializable> idList);
示例代码如下:
@Controller
public class MyController {@Autowiredprivate IUserService iUserService;@GetMapping("/get")public void get(HttpServletResponse response){boolean b = iUserService.removeById(7);boolean b2 = iUserService.removeByIds(Arrays.asList(1,2,3,4));}
}
- Update
数据更新
// 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
boolean update(Wrapper<T> updateWrapper);
// 根据 whereWrapper 条件,更新记录
boolean update(T updateEntity, Wrapper<T> whereWrapper);
// 根据 ID 选择修改
boolean updateById(T entity);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList, int batchSize);
示例代码如下:
@Controller
public class MyController {@Autowiredprivate IUserService iUserService;@GetMapping("/get")public void get(HttpServletResponse response){User user = new User();user.setId(6);user.setName("f");user.setAge("23");boolean b = iUserService.updateById(user);System.out.println(b);/** Output* true*/}
}
- Get
获取单条数据
// 根据 ID 查询
T getById(Serializable id);
// 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
T getOne(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
// 根据 Wrapper,查询一条记录
Map<String, Object> getMap(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
示例代码如下:
@Controller
public class MyController {@Autowiredprivate IUserService iUserService;@GetMapping("/get")public void get(HttpServletResponse response){User user = iUserService.getById(1);System.out.println(user.toString());/** Output* {id:1,name:a,age:12}*/}
}
- List
获取列表数据
// 查询所有
List<T> list();
// 查询列表
List<T> list(Wrapper<T> queryWrapper);
// 查询(根据ID 批量查询)
Collection<T> listByIds(Collection<? extends Serializable> idList);
// 查询(根据 columnMap 条件)
Collection<T> listByMap(Map<String, Object> columnMap);
// 查询所有列表
List<Map<String, Object>> listMaps();
// 查询列表
List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);
// 查询全部记录
List<Object> listObjs();
// 查询全部记录
<V> List<V> listObjs(Function<? super Object, V> mapper);
// 根据 Wrapper 条件,查询全部记录
List<Object> listObjs(Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录
<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
示例代码如下:
@Controller
public class MyController {@Autowiredprivate IUserService iUserService;@GetMapping("/get")public void get(HttpServletResponse response){List<User> list = iUserService.list();System.out.println(list.toString());System.out.println("===========================");Map<String, Object> map= new HashMap<>();map.put("name","a");List<User> list2 = iUserService.listByMap(map);System.out.println(list2.toString());System.out.println("===========================");List<User> list3 = iUserService.listByIds(Arrays.asList(1,2,3,4));System.out.println(list3.toString());/** Output* [{id:1,name:a,age:12}, {id:2,name:b,age:13}, {id:3,name:c,age:14}, {id:4,name:bb,age:15}, {id:5,name:ee,age:22}, {id:6,name:null,age:2}, {id:7,name:f,age:2}]* ===========================* [{id:1,name:a,age:12}]* ===========================* [{id:1,name:a,age:12}, {id:2,name:b,age:13}, {id:3,name:c,age:14}, {id:4,name:bb,age:15}]*/}
}
- Page
你需要配置分页拦截器:
@Configuration
public class MyConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor(){MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return mybatisPlusInterceptor;}
}
调用page()
方法进行分页
// 无条件分页查询
IPage<T> page(IPage<T> page);
// 条件分页查询
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
// 无条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page);
// 条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);
Page对象一共有四个构造方法,可以用来定义分页的页数和条数,你也可以调用对应的set
方法进行赋值。
//传入页数、条数
public Page(long current, long size) {}
//传入页数、条数、总数
public Page(long current, long size, long total) {}
//传入页数、条数、是否查询总数:true是、false否
public Page(long current, long size, boolean searchCount) {}
//传入页数、条数、总数、是否查询总数:true是、false否
public Page(long current, long size, long total, boolean searchCount) {}
示例代码如下:
@Controller
public class MyController {@Autowiredprivate IUserService iUserService;@GetMapping("/get")public void get(HttpServletResponse response){Page<User> userPage = new Page<>(1,3,true);Page<User> p = iUserService.page(userPage);List<User> records = p.getRecords();System.out.println(records.toString());/** Output* [{id:1,name:a,age:12}, {id:2,name:b,age:13}, {id:3,name:c,age:14}]*/}
}
当searchCount
属性为true的情况,会先去查询总数后分页。
- Count
查询总数
// 查询总记录数
int count();
// 根据 Wrapper 条件,查询总记录数
int count(Wrapper<T> queryWrapper);
示例代码如下:
@Controller
public class MyController {@Autowiredprivate IUserService iUserService;@GetMapping("/get")public void get(HttpServletResponse response){long count = iUserService.count();System.out.println(count);/** Output* 8*/}
}
关于Wrapper对象的使用在稍后的章节里详细讲解。
- Model
实体类只需继承 Model 类即可进行强大的 CRUD 操作
class User extends Model<User>{// fields...public static void main(String[] args) {User user = new User();user.insert();user.selectAll();user.updateById();user.deleteById();// ...}
}
不过在开发过程中,业务逻辑通过自动注入进行操作,实体类只用于数据传输操作。
Mapper CRUD 接口
通过封装BaseMapper (opens new window)接口实现CRUD操作。
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
- Insert
新增数据
int insert(T entity);
示例代码如下:
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){User user = new User();user.setId(10);user.setName("h");user.setAge("23");long insert = userMapper.insert(user);System.out.println(insert);/** Output* 1*/}
}
- Delete
删除数据
// 根据 entity 条件,删除记录
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
// 删除(根据ID 批量删除)
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 ID 删除
int deleteById(Serializable id);
// 根据 columnMap 条件,删除记录
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
示例代码如下:
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){//根据ID删除int deleteById = userMapper.deleteById(1);//根据ID批量删除int deleteById2 = userMapper.deleteBatchIds(Arrays.asList(1, 2, 3, 4));//根据key=value当做条件删除Map<String,Object> map = new HashMap<>();map.put("name","g");int deleteById3 = userMapper.deleteByMap(map);}
}
- Update
修改数据
// 根据 whereWrapper 条件,更新记录
int update(@Param(Constants.ENTITY) T updateEntity, @Param(Constants.WRAPPER) Wrapper<T> whereWrapper);
// 根据 ID 修改
int updateById(@Param(Constants.ENTITY) T entity);
示例代码如下:
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){User user = new User();user.setId(10);user.setName("h");user.setAge("23");long insert = userMapper.updateById(user);}
}
- Select
查询数据
// 根据 ID 查询
T selectById(Serializable id);
// 根据 entity 条件,查询一条记录
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);// 查询(根据ID 批量查询)
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 entity 条件,查询全部记录
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 查询(根据 columnMap 条件)
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
// 根据 Wrapper 条件,查询全部记录
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);// 根据 entity 条件,查询全部记录(并翻页)
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录(并翻页)
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询总记录数
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
示例代码如下:
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){//传null查询全部List<User> users = userMapper.selectList(null);//通过id查询User user = userMapper.selectById(1);//批量id查询List<User> users2 = userMapper.selectBatchIds(Arrays.asList(1,2,3,4));//根据key=value当做条件查询Map<String,Object> map = new HashMap<>();map.put("name","g");map.put("age","23");List<User> users3 = userMapper.selectByMap(map);}
}
条件构造器
再CRUD的方法中,看到很多的Wrapper参数,下面就来学习如何使用它当中参数。
QueryWrapper和UpdateWrapper
QueryWrapper(LambdaQueryWrapper)
和 UpdateWrapper(LambdaUpdateWrapper)
的父类,用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件。
- QueryWrapper
QueryWrapper 是 MyBatis-Plus 中的一个查询条件构造器,用于构建查询条件。使用 QueryWrapper 可以实现复杂的查询条件组合,例如等值条件、范围条件、模糊查询、排序等。QueryWrapper 还支持 Lambda 表达式,可以通过 Lambda 来指定字段名,减少因为字段改名而引起的错误。
使用select
方法,指定查询返回字段。
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.select("id","name");List<User> users = userMapper.selectList(wrapper);}
}
如图所示
- UpdateWrapper
UpdateWrapper 是 MyBatis-Plus 中用于构建更新操作条件的类,使用set()
方法设置要更新的字段及对应的数值。
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){UpdateWrapper<User> wrapper = new UpdateWrapper<>();wrapper.eq("id","7");wrapper.set("name","g");wrapper.set("age","20");int users = userMapper.update(wrapper);}
}
如图所示
allEq
传入Map参数,key
为数据库字段名,value
为字段值。
allEq(Map<R, V> params)
//null2IsNull:忽略空值
allEq(Map<R, V> params, boolean null2IsNull)
allEq(boolean condition, Map<R, V> params, boolean null2IsNull)
示例代码如下:
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){Map<String,Object> map = new HashMap<>();map.put("name","a");map.put("age",null);QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.allEq(map);List<User> users = userMapper.selectList(wrapper);System.out.println(users.toString());wrapper = new QueryWrapper<>();wrapper.allEq(map,false);List<User> users2 = userMapper.selectList(wrapper);System.out.println(users2.toString());/** Output* []* [{id:1,name:a,age:12}]*/}
}
执行结果如图
eq、ne
- eq:等于
=
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.eq("name","a");List<User> users = userMapper.selectList(wrapper);}
}
执行结果如图所示
- ne:不等于
<>
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.ne("name","a");List<User> users = userMapper.selectList(wrapper);}
}
执行结果如图所示
gt、ge、lt、le
- gt:大于
>
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.gt("age",21);List<User> users = userMapper.selectList(wrapper);}
}
执行结果如图
- ge:大于等于
>=
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.ge("age",21);List<User> users = userMapper.selectList(wrapper);}
}
执行结果如图
- lt:小于
<
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.lt("age",21);List<User> users = userMapper.selectList(wrapper);}
}
执行结果如图
- le:小于等于
<=
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.le("age",21);List<User> users = userMapper.selectList(wrapper);}
}
执行结果如图
between、notBetween
- between:区间
BETWEEN 值1 AND 值2
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.between("age",21,25);List<User> users = userMapper.selectList(wrapper);}
}
执行结果如图
- notBetween:非区间
NOT BETWEEN 值1 AND 值2
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.notBetween("age",21,25);List<User> users = userMapper.selectList(wrapper);}
}
执行结果如图
like、notLike、likeLeft、likeRight、notLikeLeft、notLikeRight
- like:全模糊匹配
LIKE '%值%'
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.like("name","b");List<User> users = userMapper.selectList(wrapper);}
}
执行结果如图
- notLike:全模糊不匹配
NOT LIKE '%值%'
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.notLike("name","b");List<User> users = userMapper.selectList(wrapper);}
}
执行结果如图
- likeLeft:左模糊匹配
LIKE '%值'
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.likeLeft("name","b");List<User> users = userMapper.selectList(wrapper);}
}
执行结果如图
- likeRight:右模糊匹配
LIKE '值%'
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.likeRight("name","b");List<User> users = userMapper.selectList(wrapper);}
}
执行结果如图
- notLikeLeft:左模糊不匹配
NOT LIKE '%值'
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.notLikeLeft("name","b");List<User> users = userMapper.selectList(wrapper);}
}
执行结果如图
- notLikeRight:右模糊不匹配
NOT LIKE '值%'
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.notLikeRight("name","b");List<User> users14 = userMapper.selectList(wrapper);}
}
执行结果如图
isNull、isNotNull
- isNull:是null
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.isNull("name");List<User> users = userMapper.selectList(wrapper);}
}
执行结果如图
- isNotNull:不是null
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.isNotNull("name");List<User> users = userMapper.selectList(wrapper);}
}
执行结果如图
in、notIn、inSql、notInSql
- in:
字段 IN (value.get(0), value.get(1), ...)
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.in("id",1,2,3,4,5);List<User> users = userMapper.selectList(wrapper);}
}
执行结果如图
- notIn:
字段 NOT IN (value.get(0), value.get(1), ...)
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.notIn("id",1,2,3,4,5);List<User> users = userMapper.selectList(wrapper);}
}
执行结果如图
- inSql:
字段 IN ( sql语句 )
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.inSql("id","select id from user where age <23");List<User> users = userMapper.selectList(wrapper);}
}
执行结果如图
- notInSql:
字段 NOT IN ( sql语句 )
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.notInSql("id","select id from user where age <23");List<User> users = userMapper.selectList(wrapper);}
}
执行结果如图
groupBy、orderByAsc、orderByDesc、having
- groupBy:分组
GROUP BY 字段, ...
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.groupBy("class_id");List<User> users = userMapper.selectList(wrapper);}
}
执行结果如图
- orderByAsc:排序
ORDER BY 字段, ... ASC
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.orderByAsc("id");List<User> users = userMapper.selectList(wrapper);}
}
执行结果如图
- orderByDesc:排序
ORDER BY 字段, ... DESC
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.orderByDesc("id");List<User> users = userMapper.selectList(wrapper);}
}
执行结果如图
- having:
HAVING ( sql语句 )
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.groupBy("class_id");wrapper.having("age >20");List<User> users = userMapper.selectList(wrapper);}
}
执行结果如图
or、and
使用 QueryWrapper 的 and()
和 or()
方法可以实现多个查询条件的组合
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.isNotNull("name").and(w1 -> w1.like("name", "a").eq("age", "12")).or(w2 -> w2.eq("name", "b").ge("age", "20"));List<User> users = userMapper.selectList(wrapper);}
}
如图所示
exists、notExists
- exists:拼接
EXISTS ( sql语句 )
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.exists("select * from user where id = 1");List<User> users = userMapper.selectList(wrapper);}
}
执行结果如图
- notExists:拼接
NOT EXISTS ( sql语句 )
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.notExists("select * from user where id = 1");List<User> users2 = userMapper.selectList(wrapper);}
}
执行结果如图
组合查询
我们可以使用多个条件来过滤数据,从而得到符合多个条件的结果。
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.eq("id",1);wrapper.eq("name","a");wrapper.eq("age","12");List<User> users = userMapper.selectList(wrapper);}
}
如图所示
动态条件查询
在实际的应用中,经常会遇到根据不同条件动态构建查询条件的情况。
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){String name = null;String age = "12";QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.eq("id",1);if(name != null) {wrapper.eq("name", name);}if(age != null) {wrapper.eq("age", age);}List<User> users = userMapper.selectList(wrapper);}
}
如图所示
如果你要使用XML,需要加上配置文件进行扫描
主键策略
在 MyBatis-Plus 中,主键策略可以通过 @TableId
注解来指定。主键生成策略有多种选择,常用的有如下几种:
- 数据库自增主键(默认):使用数据库自增主键的方式生成主键值,对应 MySQL 的 AUTO_INCREMENT 策略或者其他数据库的类似机制。
@TableName("user")
public class User {@TableId(value = "id", type = IdType.AUTO)private Integer id;private String name;private String age;
}
- 雪花算法生成主键:使用雪花算法生成全局唯一的主键,一般用于分布式系统中。
@TableName("user")
public class User {@TableId(value = "id", type = IdType.ASSIGN_ID)private Integer id;private String name;private String age;
}
- UUID 生成主键:使用 UUID 来生成主键值。
@TableName("user")
public class User {@TableId(value = "id", type = IdType.ASSIGN_UUID)private Integer id;private String name;private String age;
}
- 自定义生成策略:可以实现 IdentifierGenerator 接口自定义主键生成策略。
@TableName("user")
public class User {@TableId(value = "id", type = IdType.INPUT)private Integer id;private String name;private String age;
}
自定义生成类
@Component
public class CustomIdGenerator implements IdentifierGenerator {@Overridepublic Long nextId(Object entity) {//可以将当前传入的class全类名来作为bizKey,或者提取参数来生成bizKey进行分布式Id调用生成.String bizKey = entity.getClass().getName();//根据bizKey调用分布式ID生成long id = ....;//返回生成的id值即可.return id;}
}
注入bean,两种方法
@Bean
public IdentifierGenerator idGenerator() {return new CustomIdGenerator();
}
或者通过 MybatisPlusPropertiesCustomizer 自定义
@Bean
public MybatisPlusPropertiesCustomizer plusPropertiesCustomizer() {return plusProperties -> plusProperties.getGlobalConfig().setIdentifierGenerator(new CustomIdGenerator());
}
内置支持:DB2KeyGenerator、H2KeyGenerator、KingbaseKeyGenerator、OracleKeyGenerator、PostgreKeyGenerator。
@Bean
public IKeyGenerator keyGenerator() {return new H2KeyGenerator();
}
逻辑删除
逻辑删除是指在数据库中并不真正删除数据记录,而是通过标记一个字段来表示数据记录的删除状态,通常是将该字段的值设置为已删除的标识。
有两种方法可以使用逻辑删除:全局配置和指定注解
- 全局配置
在配置文件中添加全局配置
# 逻辑已删除值(默认为 1)
mybatis-plus.global-config.db-config.logic-delete-value=1
# 逻辑未删除值(默认为 0)
mybatis-plus.global-config.db-config.logic-not-delete-value=0
找到实体类字段,加上注解@TableLogic
public class User implements Serializable {private static final long serialVersionUID = 1L;private Integer id;private String name;private String age;private Integer classId;@TableLogicprivate Integer isDel;@Overridepublic String toString() {return "{id:"+id+",name:"+name+",age:"+age+"}";}
}
- 指定注解
你可以直接使用注解进行设置
public class User implements Serializable {private static final long serialVersionUID = 1L;private Integer id;private String name;private String age;private Integer classId;@TableLogic(value = "0",delval = "1")private Integer isDel;@Overridepublic String toString() {return "{id:"+id+",name:"+name+",age:"+age+"}";}
}
如果没有配置属性值,默认情况下value = "0",delval = "1"
加上注解后对应的CRUD操作会有一些变化:
- 插入: 不作限制
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){User user = new User();user.setId(8);user.setName("g");user.setAge("15");userMapper.insert(user);}
}
如图所示
- 查找: 追加
where
条件过滤掉已删除数据。
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){User user = userMapper.selectById(1);}
}
如图所示
- 更新: 追加
where
条件防止更新到已删除数据。
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){User user = new User();user.setId(8);user.setName("g");user.setAge("15");userMapper.updateById(user);}
}
如图所示
- 删除: 转变为 更新
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){userMapper.deleteById(8);}
}
如图所示
自动填充功能
自动填充功能可以用于在插入和更新操作时自动填充一些字段的值,比如创建时间、更新时间、操作人等。可以通过实现 MetaObjectHandler 接口来实现
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {@Overridepublic void insertFill(MetaObject metaObject) {LocalDateTime currentTime = LocalDateTime.now();this.strictInsertFill(metaObject, "ctime", LocalDateTime.class, currentTime);this.strictInsertFill(metaObject, "utime", LocalDateTime.class, currentTime);}@Overridepublic void updateFill(MetaObject metaObject) {LocalDateTime currentTime = LocalDateTime.now();this.strictUpdateFill(metaObject, "utime", LocalDateTime.class, currentTime);}
}
实体类加上注解@TableField(fill = FieldFill.*)
public class User implements Serializable {private static final long serialVersionUID = 1L;private Integer id;private String name;private String age;private Integer classId;private Integer isDel;@TableField(fill = FieldFill.INSERT)private LocalDateTime ctime;@TableField(fill = FieldFill.INSERT_UPDATE)private LocalDateTime utime;@Overridepublic String toString() {return "{id:"+id+",name:"+name+",age:"+age+"}";}
}
我们分别执行新增和修改操作
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){User user = new User();user.setId(8);user.setName("g");user.setAge("15");userMapper.insert(user);}
}
如图所示
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){User user = new User();user.setId(8);user.setName("g");user.setAge("15");userMapper.updateById(user);}
}
如图所示
可以看到执行新增和修改操作时都自动填充了相应的值。
FieldFill是一个枚举,有以下几种值:
public enum FieldFill {/*** 默认不处理*/DEFAULT,/*** 插入填充字段*/INSERT,/*** 更新填充字段*/UPDATE,/*** 插入和更新填充字段*/INSERT_UPDATE
}
防全表更新与删除插件
注入MybatisPlusInterceptor类,并配置BlockAttackInnerInterceptor拦截器
@Configuration
public class MyConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());return interceptor;}
}
@Controller
public class MyController {@Autowiredprivate UserMapper userMapper;@GetMapping("/get")public void get(HttpServletResponse response){User user = new User();user.setId(8);user.setName("g");user.setAge("15");userMapper.update(user,null);}
}
执行结果如图所示
MybatisX快速开发插件
MybatisX 是一款基于 IDEA 的快速开发插件,为效率而生。
安装方法:打开 IDEA,进入 File -> Settings -> Plugins -> Browse Repositories,输入 mybatisx 搜索并安装。
找到Idea最右侧,数据库连接,点击新建,输入用户名密码等信息,创建Mysql连接。
填写完毕后,点击Apply按钮。
按下列图顺序,选择显示的数据库
找到对应的表
点击MybatisX-Generator,填写路径和包名,点击下一步
然后选择Myabtis-Plus 3的相关操作,按图片勾选,点击Finish
生成效果如下