MyBatis-Plus入门笔记
MyBaits-Plus
- Lambda表达式
- 在涉及到多表的查询中,还是需要使用到MyBatis中的原生连接标签
collection
以及association
MyBatis vs JPA
- MyBatis优势
- SQL语句自由控制,灵活,性能高
- SQL与代码分离,易于阅读和维护
- 提供XML标签,支持编写动态SQL语句
- MyBatis劣势
- 简单的CRUD操作还得写SQL语句
- XML中有大量的SQL要维护
- Mybatis自身功能有限,但是支持Plugin
- JPA优势
- JPQL(移植性较好)
- 提供了很多CRUD方法、开发效率高
- 对象化程度更高
MyBaits-Plus简介
框架结构
特性
- 无侵入,损耗小、强大的CRUD操作
- 支持Lambda形式调用、支持多种数据库
- 支持主键自动生成、支持ActiveRecord模式
- 支持自定义全局通用操作、支持关键词自动转义
- 内置代码生成器、内置分页插件、内置性能分析插件
- 内置全局拦截插件、内置Sql注入剥离器
Lombook
入门
- 建库建表
- 引入依赖
- 配置
- 编码
- 测试
基本使用
- SSM传统编程模式
- 接口中写抽象方法
- XML或注解写SQL
- Service中调用接口
- Controller中调用
MyBatis-Plus 通用Mapper
新增(Create)
- mp 实体类和数据库的表对应的是驼峰命名 — > 下划线代替驼峰(createTime—>create_time)
- mp主键默认寻找为id的,
- 常用注解
- @Data:用在实体类上,set,get方法
- @TableName:指定数据库表名
- @TableId:指定当前属性为主键,mp主键默认寻找属性名为id的
- @TableFiled:指定当前属性所对应的列名
- 排除非表字段的三种方式,就是存储在实体类中,在数据库表中无对应的字段。
- transient:修饰变量
- static:修饰变量
- @TableField(exist = false):注解,表示非数据库表中字段
查询(Retrieve)
注意:所有的查询需要的参数都是数据库中表的列名。
以条件构造器作为参数的查询方法(AbstractWrapper)
-
默认复杂查询中使用的and
-
//创建wrapper对象,QueryWrapper继承自AbstractWrapper QueryWrapper<User> queryWrapper = new QueryWrapper<>(); /** * 1、名字中包含雨并且年龄小于40 * name like '%雨%' and age<40 */ @Test public void selectByWrapper() { QueryWrapper<User> queryWrapper = new QueryWrapper<>();//第一种 // QueryWrapper<User> query = Wrappers.<User>query();//第二中 queryWrapper.like("name","雨").lt("age",40); List<User> userList = userMapper.selectList(queryWrapper); userList.forEach(System.out::println); }
select中字段不全部出现的方式(wrapper.select())
-
wrapper.select(String… columns)
-
wrapper.select(Class entityClass, Predicate predicate),用来处理select应该出现的列。
-
@Test public void selectByWrapperSupper2() { QueryWrapper<User> queryWrapper = new QueryWrapper<>();//第一种 queryWrapper.like("name","雨").lt("age",40).select(User.class, info->!info.getColumn().equals("create_time")&& !info.getColumn().equals("manager_id")); List<User> userList = userMapper.selectList(queryWrapper); userList.forEach(System.out::println); }
-
条件构造器中condition的作用
- wrapper中的方法重载,使用到condition,如(
eq(boolean condition, R column, Object val)
),将判空的条件添加到condition,condition就是设置可变参数设置是否为空
创建条件构造器时传入实体对象
-
@Test public void selectByWrapperEntity() { User whereUser = new User(); whereUser.setName("刘红雨"); whereUser.setAge(32); QueryWrapper<User> queryWrapper = new QueryWrapper<>(whereUser); // queryWrapper.like("name","雨").lt("age",40); List<User> userList = userMapper.selectList(queryWrapper); userList.forEach(System.out::println); }
-
注意 entity和like之类的不能同时使用,如果需要like,模糊查询,只需要在属性上加上@TableField(condition=SqlCondition.LIKE) ,SqlCondition也是可以直接写的,
@TableField(condition = SqlCondition.LIKE) private String name;// 姓名 @TableField(condition = "%s<#{%s}") private Integer age;// 年龄
allEq用法
-
allEq(Map<R, V> params) allEq(Map<R, V> params, boolean null2IsNull) allEq(boolean condition, Map<R, V> params, boolean null2IsNull)
个别参数说明:
params
:key
为数据库字段名,value
为字段值
null2IsNull
: 为true
则在map
的value
为null
时调用 isNull 方法,为false
时则忽略value
为null
的 -
allEq(BiPredicate<R, V> filter, Map<R, V> params) allEq(BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull) allEq(boolean condition, BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull)
个别参数说明:
filter
: 过滤函数,是否允许字段传入比对条件中
params
与null2IsNull
: 同上@Test public void selectByWrapperAllEq() { QueryWrapper<User> queryWrapper = new QueryWrapper<>(); Map<String,Object> params = new HashMap<>(); params.put("name","王天风"); params.put("age",25); // queryWrapper.allEq(params); queryWrapper.allEq((k,v)->!k.equals("name"),params); List<User> userList = userMapper.selectList(queryWrapper); userList.forEach(System.out::println); }
通用Mapper
-
其他以条件构造器为参数的查询方法
-
// 根据 Wrapper 条件,查询全部记录 List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
-
/* {0}可变参数 */ @Test public void selectByWrapperMaps2() { QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.select("avg(age) avg_age","min(age) min_age","max(age) max_age").groupBy("manager_id").having("sum(age)<{0}",500); List<Map<String,Object>> userList = userMapper.selectMaps(queryWrapper); userList.forEach(System.out::println); }
-
// 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值 List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
-
// 根据 Wrapper 条件,查询总记录数 Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
-
// 根据 entity 条件,查询一条记录 T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
Lambda条件构造器
-
好处:确保数据列表的准确性,防误触功能。
-
@Test public void selectLambda() { // LambdaQueryWrapper<Object> lambda = new QueryWrapper<>().lambda();//第一种创建 // LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();//第二张 LambdaQueryWrapper<User> lambdaQuery = Wrappers.<User>lambdaQuery(); lambdaQuery.like(User::getName,"雨").lt(User::getAge,40);//where name like "雨" List<User> userList = userMapper.selectList(lambdaQuery); userList.forEach(System.out::println); }
自定义SQL
-
通过注解的方式
-
@Test public void selectMy() { LambdaQueryWrapper<User> lambdaQuery = Wrappers.<User>lambdaQuery(); lambdaQuery.like(User::getName,"王").and(lqw->lqw.lt(User::getAge,40).or().isNotNull(User::getEmail)); List<User> userList = userMapper.selectAll(lambdaQuery); userList.forEach(System.out::println); } @Select("select * from user ${ew.customSqlSegment}") List<User> selectAll(@Param(Constants.WRAPPER)Wrapper<User> wrapper);
-
-
通过Mapper的形式(xml配置)
-
首先需要在application配置文件中添加上mapper文件的映射路径
-
mybatis-plus: mapper-locations: classpath*:mybatis/mapper/*.xml
-
-
其次编写mapper文件,
{ew.customSqlSegment}
查询不需要加上where,会自动判断-
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <!--命名空间绑定接口--> <mapper namespace="com.mp.dao.UserMapper"> <select id="selectAll" resultType="com.mp.entity.User"> select * from user ${ew.customSqlSegment} </select> </mapper>
-
-
MyBatis分页介绍
- Mybatis逻辑分页:Mybatis分页,内存分页,把符合条件的数据到内存中,返回你所需要的,数据量过大,产生问题:消耗内存;查询数据慢。
MP分页插件实现物理分页
-
配置插件,配置
PaginationInterceptor
-
/** * @Description * @Author tangmf * @Date 2020/1/14 10:47 */ @Configuration public class MyBatisPlusConfig { @Bean // 加入到spring容器管理 public PaginationInterceptor paginationInterceptor() { return new PaginationInterceptor(); } }
-
-
底层方法
-
// 根据 entity 条件,查询全部记录(并翻页)返回实体 IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 根据 Wrapper 条件,查询全部记录(并翻页) 返回Map IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
-
@Test public void selectPage() { QueryWrapper<User> queryWrapper = new QueryWrapper<>();//第一种 queryWrapper.ge("age",26); Page<User> userPage = new Page<>(1, 2); /*IPage<User> iPage = userMapper.selectPage(userPage, queryWrapper); System.out.println("总页数:"+iPage.getPages()); System.out.println("总记录数:"+iPage.getTotal()); List<User> userList = iPage.getRecords(); userList.forEach(System.out::println);*/ IPage<Map<String,Object>> iPage = userMapper.selectMapsPage(userPage, queryWrapper); System.out.println("总页数:"+iPage.getPages()); System.out.println("总记录数:"+iPage.getTotal()); List<Map<String,Object>> userList = iPage.getRecords(); userList.forEach(System.out::println); }
-
不需要总记录数,只需要记录
-
public Page(long current, long size, boolean isSearchCount) { this(current, size, 0, isSearchCount); }
-
-
自定义分页语句,写在UserMapper中,多表查询类似,xml中写多表查询即可
-
IPage<User> selectUserPage(Page<User> userPage,@Param(Constants.WRAPPER)Wrapper<User> wrapper);
-
@Test public void selectMyPage() { QueryWrapper<User> queryWrapper = new QueryWrapper<>();//第一种 queryWrapper.ge("age",26); Page<User> userPage = new Page<>(1, 2,false); //调用xml中的 IPage<User> iPage = userMapper.selectUserPage(userPage, queryWrapper); System.out.println("总页数:"+iPage.getPages()); System.out.println("总记录数:"+iPage.getTotal()); List<User> userList = iPage.getRecords(); userList.forEach(System.out::println); }
-
-
更新(Update)
-
根据id更新
-
// 根据 ID 修改 int updateById(@Param(Constants.ENTITY) T entity);
-
@Test public void updateById() { User user = new User(); user.setId(1088248166370832385L); user.setAge(26); user.setEmail("wtf2@baomidou.com"); int rows = userMapper.updateById(user); System.out.println("影响记录数:" + rows); }
-
-
以条件构造器作为参数的更新方法
-
主要使用的是UpdateWrapper。
-
// 根据 whereEntity 条件,更新记录,实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句) int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);
-
主要运用于更新实体
-
@Test public void updateByWrapper() { UpdateWrapper<User> updateWrapper = new UpdateWrapper<>(); updateWrapper.eq("name", "李艺伟").eq("age", 28); User user = new User(); user.setEmail("lyw2@baomidou.com"); user.setAge(29); int rows = userMapper.update(user, updateWrapper); System.out.println("影响记录数:" + rows); }
-
-
条件构造器中set方法使用
-
更新少量字段使用
-
@Test // 只需要更新一个属性,不需要去创建对象 public void updateByWrapper2() { UpdateWrapper<User> updateWrapper = new UpdateWrapper<>(); updateWrapper.eq("name", "李艺伟").eq("age", 29).set("age", "30"); int rows = userMapper.update(null, updateWrapper); System.out.println("影响记录数:" + rows); }
-
-
lambda方式使用
-
LambdaUpdateWrapper
,主要用于防误写功能,属性名不需要自己书写 -
@Test // Lambda方式 加入防误写功能 public void updateByWrapperLambda() { LambdaUpdateWrapper<User> lambdaUpdate = Wrappers.<User> lambdaUpdate(); lambdaUpdate.eq(User::getName, "李艺伟").eq(User::getAge, 30).set(User::getAge, 31); int rows = userMapper.update(null, lambdaUpdate); System.out.println("影响记录数:" + rows); }
-
LambdaUpdateChainWrapper
,直接使用,不需要创建对象 -
@Test public void updateByWrapperLambdaChain() { boolean update = new LambdaUpdateChainWrapper<User>(userMapper).eq(User::getName, "李艺伟") .eq(User::getAge, 31).set(User::getAge, 32).update(); System.out.println("是否成功:" + update); }
-
删除(Delete)
-
根据id删除的方法
-
@Test public void deleteById() { int rows = userMapper.deleteById(0L); System.out.println("删除条数:" + rows); }
-
-
其他普通删除方法
-
map删除,为where条件
-
@Test public void deleteByMap() { HashMap<String, Object> columnMap = new HashMap<>(); columnMap.put("name","王天风1"); columnMap.put("age",26); int rows = userMapper.deleteByMap(columnMap); System.out.println("删除条数:" + rows); }
-
删除多个
-
// 删除(根据ID 批量删除) int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList); @Test public void deleteByIds() { int rows = userMapper.deleteBatchIds(Arrays.asList(1094590409767661571L, 1094590409767661572L)); System.out.println("删除条数:" + rows); }
-
-
以条件构造器为参数的删除方法
-
wrapper设置删除的where条件
-
@Test public void deleteByWrapper() { LambdaQueryWrapper<User> lambdaQuery = Wrappers.<User> lambdaQuery(); lambdaQuery.eq(User::getAge, 27).or().gt(User::getAge, 41); int rows = userMapper.delete(lambdaQuery); System.out.println("删除条数:" + rows); }
-
ActiveRecord模式
AR探索
-
AR模式简介:领域模型模式,特点是一个模型类对应关系型数据库中的一个表,模型类的实例对应表中的一行记录。简单来说,通过实体类对象,直接进行表的增删改查操作,方便开发人员的开发。
-
要求:
-
实体类需要继承Model类
-
必须存在对应的原始mapper并继承baseMapper并且可以使用的前提下
-
@EqualsAndHashCode(callSuper = false) public class User extends Model<User> {}
-
MP中AR模式的实现
-
不需要在注入UserMapper就可以完成操作。增删改查方法会调用model类中的各种方法。有些方法,需要看原型去了解其使用与wrapper中的有一些的区别。
-
@Test public void insert() { User user = new User(); user.setName("向北"); user.setAge(26); user.setEmail("xb@baomidou.com"); user.setManagerId(1088248166370832385L); user.setCreateTime(LocalDateTime.now()); boolean insert = user.insert(); System.out.println("是否成功:" + insert); } @Test public void selectById() { User user = new User(); User user1 = user.selectById(0L); System.out.println(user1); System.out.println(user1 == user); }
主键策略
-
MP支持的主键策略介绍,主要使用到的是IdType来设置主键
-
注意:局部主键策略优先级高于全局主键策略
-
局部主键策略实现
-
需要设置数据库列自增
-
alter TABLE `user` CHANGE COLUMN id id BIGINT(20) auto_increment;
-
-
属性使用
@TableId(type = IdType.AUTO)
-
-
全局主键策略实现
-
在application.yml配置文件中使用,主要是因为需要多个实体的主键策略使用
-
#配置全局主键策略 global-config: db-config: id-type: id_worker
-
MP配置
-
基本配置,运用官方帮助文档进行设置
-
进阶配置
-
在 update,insert,delete,select 的时候的字段验证策略 目前没有默认值,等 {@link #fieldStrategy} 完全去除掉,会给个默认值 NOT_NULL 没配则按 {@link #fieldStrategy} 为准
-
field-strategy: ignored
-
表名前缀
-
#配置全局主键策略 global-config: db-config: id-type: id_worker table-prefix: mp_
-
-
tableUnderline
表名、是否使用下划线命名,默认数据库表使用下划线命名
-
-
DB策略配置
通用Service
-
基本方法
-
UserService extends IService<T> UserServiceImpl extendsServiceImpl<M extends BaseMapper<T>, T> UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService 操作实体,操作Mapper
-
特殊情况
-
@Test public void getOne() { User user = userService.getOne(Wrappers.<User> lambdaQuery().gt(User::getAge, 25),false); System.out.println(user); }
-
-
批量操作方法(Batch)
-
@Test public void Batch() { User user1 = new User(); user1.setName("徐丽1"); user1.setAge(28); User user2 = new User(); user2.setId(1094592041087729672L); user2.setName("徐2"); user2.setAge(29); List<User> userList = Arrays.asList(user1, user2); // boolean b = userService.saveBatch(userList); boolean b = userService.saveOrUpdateBatch(userList); System.out.println("是否成功:" + b); }
-
-
链式调用方法(Lambda)
-
@Test//查询 public void chain() { List<User> userList = userService.lambdaQuery().ge(User::getAge, 25).like(User::getName, "雨").list(); userList.forEach(System.out::println); } @Test//更新 public void chain1() { boolean update = userService.lambdaUpdate().eq(User::getAge, 25).set(User::getAge, 26) .update(); System.out.println(update); } @Test //删除 public void chain2() { boolean update = userService.lambdaUpdate().eq(User::getAge, 29).remove(); System.out.println(update); }
-