MyBatis-Plus使用记录
目录
警告
本文最后更新于 2023-03-06,文中内容可能已过时,请谨慎使用。
BaseMapper
MyBatis-Plus
提供了一个通用的增删改查的Mapper
,可以通过自定义Mapper接口继承BaseMapper<T>
完成基础的增删改查
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
Select
// 根据 ID 查询
T selectById(Serializable id);
// 根据 entity 条件,查询一条记录, 如果查询结果超过1条则会报TooManyResultsException异常
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);
// 根据 Wrapper 条件,查询总记录数
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
样例:
// 查询表中所有数据
List<User> userList = userMapper.selectList(null);
userList.forEach(System.out::println);
// 根据id查询,例如id=2的用户信息
userMapper.selectById(2);
// 多条件查询
// 根据id和name进行查询
// 方法1: 使用QueryWrapper
QueryWrapper<User> qw = new QueryWrapper<>();
qw.eq("id",id);
qw.eq("name",name);
userMapper.selectList(qw);
// 方法2: 使用selectByMap
// 返回一个List
HashMap<String,Object> map = new HashMap<>();
map.put("id",1);
map.put("name","Jone");
System.out.println(userMapper.selectByMap(map));
// 查询有多少条数据
System.out.println("mapper.selectCount(null) = " + userMapper.selectCount(null));
// selectList查询部分字段,会返回所有的,没查询的值为null
// 而selectMaps只会返回你查询的字段
// 查询多个字段的值,null表示返回全部字段
System.out.println("mapper.selectMaps(null) = " + userMapper.selectMaps(null));
// 查询部分字段
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select("name", "age");
List<Map<String, Object>> users = userMapper.selectMaps(queryWrapper);
users.forEach(System.out::println);
// 查询单字段的值,null表示返回主键值
// 注意,如果填了多个字段,只返回第一个字段的值
System.out.println("mapper.selectObjs(null) = " + userMapper.selectObjs(null));
// 表中是否存在数据
System.out.println("mapper.exists(null) = " + userMapper.exists(null));
// 同时查询多个id的用户数据
List<Long> list = new ArrayList<>();
list.add(1L);
list.add(2L);
list.add(3L);
System.out.println("userMapper.selectBatchIds(list) = " + userMapper.selectBatchIds(list));
Insert
// 插入一条记录
int insert(T entity);
样例:
User u = new User(7L,"admin",18,"xxx");
userMapper.insert(u);
update
// 根据whereEntity条件,更新记录
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);
// 根据ID修改
int updateById(@Param(Constants.ENTITY) T entity);
样例:
# 根据用户id找到该用户,然后修改他的名字
UpdateWrapper<User> userUpdateWrappers = new UpdateWrapper<>();
userUpdateWrappers.eq("id",2).set("name","bbb");
System.out.println(userMapper.update(null,userUpdateWrappers));
# 根据id修改其他字段值
User u = new User(1,"aaa",19,"111@qq.com");
userMapper.updateById(u);
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);
样例:
// 根据id进行删除
// 返回值为受影响的行数
System.out.println(userMapper.deleteById(2));
// 利用键值对进行多条件删除
HashMap<String,Object> map = new HashMap<>();
map.put("id",3);
map.put("name","Tom");
System.out.println("userMapper.deleteByMap(map) = " + userMapper.deleteByMap(map));
// 根据id列表批量删除数据
List<Long> list = new ArrayList<>();
list.add(1L);
list.add(3L);
list.add(5L);
System.out.println("userMapper.deleteBatchIds(list) = " + userMapper.deleteBatchIds(list));
// 利用QueryWrapper删除
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("id",1);
queryWrapper.eq("name","Jone");
System.out.println("userMapper.delete(queryWrapper) = " + userMapper.delete(queryWrapper));
设置id自增
-
@TableName("表名")
在类名和表名不一致的情况下,可以在类名上添加此注解指定表名 -
@TableId("id名称")
可以在属性上指定id
所在的字段,在id
和表中的id
不一致时,可以在括号中,@TableId(type = IdType.XXX)
可以指定插入主键值的生成策略,默认为雪花算法
MyBatis-Plus
默认实现5种主键生成策略,分别是:
AUTO
,配合数据库设置自增主键,可以实现主键的自动增长INPUT
,由用户输入NONE
,不设置,等同于INPUTASSIGN_ID
,只有当用户未输入时,采用雪花算法生成一个适用于分布式环境的全局唯一主键,类型可以是String
和number
ASSIGN_UUID
,只有当用户未输入时,生成一个String类型的主键,但不保证全局唯一
@TableId(type = IdType.AUTO)
private Integer id;
如果表创建的时候没有设置自增,需要修改id
列为自增
IService
一个通用的Service
接口,MyBatis Plus
提供了一个实现类为:ServiceImpl<M extends BaseMapper<T>, T>
@Service
public class UserService extends ServiceImpl<UserMapper, User> {
}
简单使用
@Test
void insertData() {
// 存入一个user
User user = new User(null,"zzz",18,"aa");
// service.save(user);
// 批量存入
List<User> list = new ArrayList<>();
list.add(user);
list.add(user);
list.add(user);
service.saveBatch(list);
// 查看所有数据
service.list().forEach(System.out::println);
}
@Test
void insertUpdate() {
System.out.println("service.list() = " + service.list());
User user = new User(null, "admin", 20, "xxx@qq.com");
// 根据主键进行插入或者更新某条记录,如果数据库中不存在这个主键,那么将会进行插入;
// 如果存在这个主键,就进行更新这条记录
service.saveOrUpdate(user);
System.out.println("service.list() = " + service.list());
}
@Test
void insertBatch() {
service.list().forEach(System.out::println);
}
@Test
void select() {
System.out.println("service.count() = " + service.count());
System.out.println("service.list() = " + service.list());
System.out.println("service.listMaps() = " + service.listMaps());
System.out.println("service.listObjs() = " + service.listObjs());
System.out.println("service.getById(1) = " + service.getById(1));
}
@Test
void delete() {
service.removeById(1);
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
service.removeByIds(list);
list.add(4);
service.removeBatchByIds(list);
System.out.println("service.list() = " + service.list());
HashMap<String, Object> map = new HashMap<>();
map.put("id", 5);
map.put("name","Billie");
service.removeByMap(map);
System.out.println("service.list() = " + service.list());
}
条件构造器 wrapper
@Test
void test() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.ge("id", 5)
.or(qw -> qw.ge("age",25).le("age",100));
// 小于
// queryWrapper.lt("id", 3);
// 小于等于
// queryWrapper.le("id", 3);
// 大于
// queryWrapper.gt("id", 2);
// 大于等于
// queryWrapper.ge("id", 3);
// 等于
// queryWrapper.eq("id", 3);
// 不等于
// queryWrapper.ne("id", 2);
// 联合起来写,代表大于等于2且小于等于5,且不等于3
// queryWrapper.ge("id", 2)
// .le("id", 5)
// .ne("id", 3);
// between条件
// queryWrapper.between("id", 2, 4); // id在2到4
// like条件
// queryWrapper.like("name", "J%");
// not like
// queryWrapper.notLike("name", "%a%");
// 查询某几个字段
// queryWrapper.select("id", "name");
/*
也可以使用group by,select中也可以写别名
*/
// queryWrapper.groupBy("age");
// queryWrapper.select("age 年龄", "count(*) 数量");
// queryWrapper.select("age as 年龄", "count(*) as 数量");
// in的用法
// queryWrapper.in("id", 2, 3, 4);
// queryWrapper.in("id", List.of(2, 3, 4));
// not in
// queryWrapper.notIn("id", 2, 3, 5);
// queryWrapper.notIn("id", List.of(2, 3, 5)); // jdk 9新API
// 排序
// 正序
// queryWrapper.orderBy(true, true, "id");
// queryWrapper.orderByAsc("id");
// 倒序
// queryWrapper.orderBy(true, true, "id");
// queryWrapper.orderByDesc("id");
// ((id >= ?) OR (age >= ? AND age <= ?))
// queryWrapper.ge("id", 5)
// .or()
// .ge("age", 25)
// .le("age", 100);
// queryWrapper.ge("id", 5)
// .or(wrapper -> wrapper.ge("age", 25).le("age", 100));
// queryWrapper.isNull("列名").isNotNull("列名")
userMapper.selectList(queryWrapper).forEach(System.out::println);
}
LambdaQueryWrapper
避免手打的字段名出错,其他功能和QueryWrapper
一致
@Test
void lambdaQueryWrapperTest() {
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
lqw.select(User::getName,User::getAge);
userMapper.selectMaps(lqw).forEach(System.out::println);
}
条件组装
Mybatis plus
提供了条件组装,只有条件为true
时才会组装这条sql
:
只有第一个参数 condition
成立时才进行 sql
拼接
@Test
void condition() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
String name = "名称";
Integer minAge = 10, maxAge = 1500;
/**
* 如果名字不为空,会按照名称进行查询
* 如果最小年龄不为空,同时也会将这个条件加进去
* 如果最大年龄不会空,也会将这个条件加进去
*/
queryWrapper.eq(name != null, "name", name);
queryWrapper.ge(minAge != null, "age", minAge);
queryWrapper.le(maxAge != null, "age", maxAge);
userMapper.selectList(queryWrapper);
}
查询最小值和最大值
// 查询用户年龄的最大值和最小值
QueryWrapper<User> qw = new QueryWrapper<>();
qw.select("max(age) as max,min(age) as min");
List<Map<String, Object>> res = userMapper.selectMaps(qw);
System.out.println(Integer.valueOf(res.get(0).get("max").toString()));
System.out.println(Integer.valueOf(res.get(0).get("min").toString()));
分页
新增一个分页配置类
@Configuration
public class MybatisConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 数据库类型为mysql
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
分页查询api
/**
*
* @param page 分页查询条件(可以为 RowBounds.DEFAULT)
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
// 根据 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);
方法需要传入两个参数:
IPage<T>
Wrapper<T>
IPage<T>
可以使用实现类 Page<T>
,Wrapper<T>
跟上面的一样使用 QueryWrapper<T>
即可
Page<T>
无参构造方法默认页码为current=1
,每页有size=10
条数据,可以传入指定页码和页大小
@Test
public void selectByWrapperPage() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
Page<User> page = new Page<>(1,10);
IPage<User> iPage = userMapper.selectPage(page, queryWrapper);
System.out.println("总页数: " + iPage.getPages());
System.out.println("数据总数: " + iPage.getTotal());
// 返回分页数据
List<User> userList = iPage.getRecords();
userList.forEach(System.out::println);
// 获取分页的其他信息
System.out.println("当前页号 = " + iPage.getCurrent());
System.out.println("页大小 = " + iPage.getSize());
}
自定义SQL分页
注意事项:
- 将
Mapper
接口中的返回值设置为Page<类型>
- 第一个参数设置为
Page<类型> page
- 其他地方不变
- 需要注意的是,自己写的
sql
语句末尾一定不要添加;
,因为分页是在sql
语句末尾进行追加的sql
语句
这里我们使用注解方式实现,也可以通过xml注入的方式实现
@Mapper
public interface UserMapper extends BaseMapper<User> {
/**
* 只对超过age的数据进行分页处理
* @return 分页器
*/
@Select("select * from user where age >= ${age}")
Page<User> selectByAge(Page<User> page, Integer age);
}
测试使用
@Test
public void selectByWrapperPageByAge() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
Page<User> page = new Page<>(1,3);
// 这里使用我们自定义的分页
IPage<User> iPage = userMapper.selectByAge(page,25);
iPage.getRecords().forEach(System.out::println);
System.out.println("总页数: " + iPage.getPages());
System.out.println("数据总数: " + iPage.getTotal());
// 返回分页数据
List<User> userList = iPage.getRecords();
userList.forEach(System.out::println);
// 获取分页的其他信息
System.out.println("当前页号 = " + iPage.getCurrent());
System.out.println("页大小 = " + iPage.getSize());
}
多数据源配置
导入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.6.1</version>
</dependency>
添加配置
spring:
datasource:
dynamic:
primary: master #设置默认的数据源或者数据源组,默认值即为master
strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
datasource:
master:
url: jdbc:mysql://xx.xx.xx.xx:3306/dynamic
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
slave_1:
url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
slave_2:
url: ENC(xxxxx) # 内置加密,使用请查看详细文档
username: ENC(xxxxx)
password: ENC(xxxxx)
driver-class-name: com.mysql.jdbc.Driver
#......省略
#以上会配置一个默认库master,一个组slave下有两个子库slave_1,slave_2