Mybatis-plus框架,简称mp。mp是mybatis的一种增强工具。
优点:简化开发,提高开发效率;在只用到单表操作的业务环境下,不需要写crud;不需要构建mapper的映射文件
1)数据库环境准备【mp_db】
2)创建SpringBoot工程,引入MybatisPlus的启动依赖【mybatis-plus-boot-starter】
mysql mysql-connector-java5.1.26 org.projectlombok lomboktrue org.springframework.boot spring-boot-starter-testtest com.baomidou mybatis-plus-boot-starter3.4.1
3)在yml中编写DataSource相关配置【spring的jdbc】
4)编写mapper【mapper接口需要继承一个类,这个类已经实现了单表的各种操作,所以无需再构建单表操作的映射文件】
5)测试【增、删、改、查】
@TableId:指定当前表的主键【主键生成策略】
- 标识实体类中主键对应属性;
- 定义主键生成策略;【type=
* IdType.NONE/ASSIGN_ID:默认情况下使用雪花算法 * IdType.AUTO:使用数据库的主键自增 * IdType.INPUT:由用户自己指定主键大小 * ASSIGN_UUID:使用UUID生成一个全局唯一字符串
】
@TableField:指定 java类的属性 和 数据库字段 的映射【属性名和表列名不一致】
@TableName("tb_user") // 指定表名
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String userName;//数据库:user_name 驼峰映射
@TableField(fill = FieldFill.INSERT_UPDATE)
private String password;//数据库:password 名称一样
@TableField("t_name")
private String name;//数据库里是t_name,必须用注解映射
private Integer age;//数据库:password 名称一样
// 忽略此字段
private String email;
}
4、mp单表的增删改 增:insert(T)
//【1】插入操作:insert()
@Test
public void testInsert(){
User user = User.builder().userName("liuyan")
.age(23)
.email("liuyan@163.com")
.name("柳岩")
.password("123456")
.build();
int i=userMapper.insert(user);
if (i>0) {
System.out.println("添加成功!");
}
}
删:deleteById(int id); deleteBatchIds(List list) deleteByMap(Map map);
//【2】删除操作
//1.根据id删除:deleteById(int i)
@Test
public void testDelete01(){
int id=22;
int i=userMapper.deleteById(id);
if(i>0)
System.out.println("删除成功!");
}
//2.根据id集合删除:deleteBatchIds(List list)
@Test
public void testDelete02(){
ArrayList listId = new ArrayList<>();
Collections.addAll(listId,23,24,25);//一次性添加多个元素
int i=userMapper.deleteBatchIds(listId);
if(i>0)
System.out.println("删除成功!");
}
//3.根据map构成条件删除:deleteByMap(Map map)
@Test
public void testDelete03(){
HashMap map = new HashMap<>();
//map集合作为删除条件【键=数组库字段名 值=数组库字段值】
map.put("user_name","liuyan");
int i=userMapper.deleteByMap(map);
if(i>0)
System.out.println("删除成功!");
}
改:updateById(T)
只更新实体类中存在的数据,如果对应的属性为null,不更新;
/【3】更改操作:updateById
//只更新实体类中存在的数据,如果对应的属性为null,不更新;
@Test
public void testUpdate(){
//根据主键更新
User user=User.builder().id(16L).userName("zhaoqishang").build();
int i=userMapper.updateById(user);
if(i>0)
System.out.println("修改成功!");
else
System.out.println("修改失败!");
}
5、mp单表的查询【分页、逻辑、模糊、排序、限定】
1) 分页查询(无条件):selectPage(Page,null)
【1】配置类:分页拦截器 {在主配置类中设置Bean}
@Configuration
@MapperScan("com.itheima.mapper")
public class MpConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
// paginationInterceptor.setOverflow(false);
// 设置最大单页限制数量,-1不受限制
paginationInterceptor.setMaxLimit(-1L);
interceptor.addInnerInterceptor(paginationInterceptor);
return interceptor;
}
}
【2】先分页、再查询、最后获取分页信息
@Test
public void testPageSelect(){
//1、设置分页:每页5条,初始展示第1页【先分页再查询】
Page page = new Page<>(1,5);
//2、开始查询; 参数1:页面设置;参数2:条件设置,相当于sql中where语句【此处无条件,null】
Page userPage = userMapper.selectPage(page,null);
//3、获取分页查询后的数据信息
// 获取分页数据信息
List userList = page.getRecords();
for (User user : userList) {
System.out.println(user);
}
// 当前页
long current = page.getCurrent();
System.out.println("当前页数是:"+current);
// 每页显示条数
long size = page.getSize();
System.out.println("每页数据数量:"+size);
// 总条数
long total = page.getTotal();
System.out.println("当前查询数据总数:"+total);
// 总页数
long pages = page.getPages();
System.out.println("总共页数:"+pages);
}
2)模糊查询:selectList(wrapper) + 逻辑转换符
逻辑转换符:
@Test
public void testQueryWrapper(){
//1、建立QueryWrapper对象 泛型为User
QueryWrapper wrapper = new QueryWrapper<>();
//2、条件筛选
wrapper.like("user_name","伤")
.eq("password","123456")
.in("age",19,25,29)
.orderByDesc("age");
//3、查询所有:selectList()
List users = userMapper.selectList(wrapper);
//4、遍历
for (User user : users) {
System.out.println("user = " + user);
}
}
解析:QueryWrapper对象相当于sql语句中where条件,但是它的限制——
QueryWrapper查询数据时,需要手写对应表的 数据库字段,
一旦之后更改了数据库的列名,也就是表结构更改后,那么对应的代码修改量也会变大,维护性较差
[改进方案]____:
LamQueryWrapper 查询数据时,用实体类的get()方法 代替 数据库字段
例如:
eq("id",18) >> eq(User::getId,18)
in("age",(1,2,3)) >> in(User::getAge,(1,2,3))
//上述查询用LambdaQueryWrapper()完善后
@Test
public void testLambdaQueryWrapper(){
//1、建立QueryWrapper对象 泛型为User
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
//2、条件筛选
wrapper.like(User::getName,"伤")
.eq(User::getPassword,"123456")
.in(User::getAge,19,25,29)
.orderByDesc(User::getAge);
//3、查询所有:selectList()
List users = userMapper.selectList(wrapper);
//4、遍历
for (User user : users) {
System.out.println("user = " + user);
}
}
3)逻辑查询: or[or()]
@Test
public void testLambdaQueryWrapper02(){
//1、建立QueryWrapper对象 泛型为User
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
//2、条件筛选
wrapper.like(User::getName,"伤")
.or()
.in(User::getAge,19,25,29)
.orderByDesc(User::getAge);
//3、查询所有:selectList()
List users = userMapper.selectList(wrapper);
//4、遍历
for (User user : users) {
System.out.println("user = " + user);
}
}
逻辑转换符or:主动调用or(),说明下一个方法为【或条件】,默认就是and连接!
【4】排序查询: orderByAsc() orderByDesc()
@Test
public void testLambdaQueryWrapper03(){
//1、建立QueryWrapper对象 泛型为User
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
//2、条件筛选
wrapper.orderByAsc(User::getAge)
.orderByDesc(User::getId);
//3、查询所有:selectList()
List users = userMapper.selectList(wrapper);
//4、遍历
for (User user : users) {
System.out.println("user = " + user);
}
}
【5】限定查询:select()
@Test
public void testLambdaQueryWrapper04(){
//1、建立QueryWrapper对象 泛型为User
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
//2、条件筛选
wrapper.like(User::getName,"伤")
.or()
.in(User::getAge,19,25,29)
.orderByDesc(User::getAge)
.select(User::getId,User::getName);
//3、查询所有:selectList()
List users = userMapper.selectList(wrapper);
//4、遍历
for (User user : users) {
System.out.println("user = " + user);
}
}
【5】分页条件查询:selectPage(Page,LambdaQueryWrapper)
@Test
public void testLambdaQueryWrapper05(){
//1、建立QueryWrapper对象和Page对象 泛型为User
Page page = new Page<>(2,3);//【先分页再查询】
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
//2、条件筛选
wrapper.like(User::getName,"伤")
.or()
.in(User::getAge,19,25,29)
.orderByDesc(User::getAge)
.select(User::getId,User::getName);
//3、分页条件查询:selectPage()
Page userPage = userMapper.selectPage(page,wrapper);
//4、获取分页数据信息:getRecords()
List userList = page.getRecords();
for (User user : userList) {
System.out.println(user);
}
long current = page.getCurrent();
System.out.println("当前页数是:"+current);
// 每页显示条数
long size = page.getSize();
System.out.println("每页数据数量:"+size);
// 总条数
long total = page.getTotal();
System.out.println("当前查询数据总数:"+total);
// 总页数
long pages = page.getPages();
System.out.println("总共页数:"+pages);
}
6、mp封装service层
MP实现Service封装【所有的crud在参数中就已经实现!】 1.定义一个服务扩展接口,该接口继承公共接口IService; 2.定义一个服务实现类,该类继承ServiceImpl,并实现自定义的扩展接口; 注意事项: 1.ServiceImpl父类已经注入了UserMapper对象,名称叫做baseMapper, 所以当前实现类直接可以使用baseMapper完成操作 2.因为ServiceImpl已经实现了IService下的方法,所以当前服务类没有必要再次实现 主要Api: 增—— save(T):boolean 保存单条操作【增加操作】 saveBatch(Collection ):boolean 批量保存操作【批量增加】 删—— removeById(Serializable):boolean 根据id删除 removeByMap(Map ):boolean 根据指定条件删除 改—— updateById(T):boolean 根据id更新【如果id不存在,更新失败】 update(Wrapper ):boolean 根据wrapper条件更新【wrapper只是筛选条件,要想更新必须set:wrapper.set】 查—— getById(Serializable):T 根据id查询 listByIds(Collection extends Serializable> lsit):List 根据id集合查询 getOne(Wrapper ):T 根据指定条件,查询符合条件的某一条信息 list(Wrapper ):List 根据指定条件,查询所有符合改条件的信息 page(E,Wrapper):E 将E按照条件Wrapper分页查询
目的:
- 开发更加快捷,对业务层也进行了封装Service层注入mapper ;
- 业务层开发时,提供的接口和实现类,编码更加高效
操作步骤:
1.定义一个服务扩展接口,该接口继承公共接口IService;
public interface UserService extends IService{ }
2.定义一个服务实现类,该类继承ServiceImpl
@Service //继承在前,实现在后 public class UserServiceImpl extends ServiceImplimplements UserService{}
使用: 测试类中使用时不需要注入mapper,但是Service。实际应用中,因为业务开发都在Service层中,所以不需要@Autowired注入,只要定义一个Service的对象即可
下面主要Api的测试:
//【1】 save(T):boolean 保存单条操作【增加操作】
@Test
public void testUserService01(){
User user1 = User.builder().name("wangwu1").userName("laowang2").
email("444@163.com").age(20).password("333").build();
boolean isSuccess = userService.save(user1);
System.out.println(isSuccess?"保存成功":"保存失败");
}
//【2】saveBatch(Collection):boolean 批量保存操作【批量增加】
@Test
public void testUserService02(){
User user1 = User.builder().name("wangwu2").userName("laowang2").
email("444@163.com").age(20).password("333").build();
User user2 = User.builder().name("wangwu3").userName("laowang3").
email("444@163.com").age(20).password("333").build();
boolean isSuccess = userService.saveBatch(Arrays.asList(user1, user2));
System.out.println(isSuccess?"保存成功":"保存失败");
}
//【3】removeById(Serializable):boolean 根据id删除
@Test
public void testUserService03(){
int id=31;
boolean result = userService.removeById(id);
System.out.println("result = " + result);
}
//【4】removeByMap(Map):boolean 根据指定条件删除
@Test
public void testUserService04(){
HashMap map = new HashMap<>();
map.put("id","32");
boolean result = userService.removeByMap(map);
System.out.println("result = " + result);
}
//【5】updateById(T):boolean 根据id更新一条数据【如果id不存在,更新失败】
@Test
public void testUserService05(){
//将id为30的user_name修改为:老王
User user = User.builder().userName("老王").id(30L).build();
boolean result = userService.updateById(user);
System.out.println("result = " + result);
}
//【6】update(Wrapper):boolean 根据wrapper条件批量更新【wrapper.set】
@Test
public void testUserService06(){
//将id为{1,3,5}的age修改为:40 LambdaUpdateWrapper实现
LambdaUpdateWrapper wrapper = new LambdaUpdateWrapper<>();
wrapper.in(User::getId,Arrays.asList(1l,3l,5l)).set(User::getAge,40);
boolean result = userService.update(wrapper);
System.out.println("result = " + result);
}
//【7】根据id查询
@Test
public void testUserService07(){
int id=15;
User user = userService.getById(id);
System.out.println("user = " + user);
}
//【8】listByIds(Collection extends Serializable> lsit):List 根据id集合批量查询
@Test
public void testUserService08(){
ArrayList list = new ArrayList<>();
Collections.addAll(list,1,3,5);
List userList = userService.listByIds(list);
for (User user : userList) {
System.out.println("user = " + user);
}
}
//【9】getOne(Wrapper):T 根据指定条件,查询符合条件的某一条信息
// ***getOne:sql查询的结果必须为1条或者没有,否则报错 !!!!***
@Test
public void testUserService09(){
//查询年龄<19的用户【必须只有一个,如果有多个用户年龄<19,查询报错!!】
// LambdaQueryWrapper实现
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
wrapper.lt(User::getAge, 19);
User one = userService.getOne(wrapper);
System.out.println(one);
}
//【10】list(Wrapper):List 根据指定条件,查询所有符合改条件的信息
@Test
public void testUserService10(){
//查询id:1~5中,年龄=20的用户
// LambdaQueryWrapper实现
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
ArrayList idList = new ArrayList<>();
Collections.addAll(idList,1,2,3,4,5);
wrapper.in(User::getId,idList).eq(User::getAge,20);
List userList = userService.list(wrapper);
for (User user : userList) {
System.out.println("user = " + user);
}
}
//【11】page(E,Wrapper):E 将E按照条件Wrapper分页查询 先分页,在查询
@Test
public void testUserService11(){
//1.Page分页
Page userPage = new Page<>(1, 4);
//2.Wrapper条件筛选
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
wrapper.lt(User::getAge,35);
//3.查询
Page page = userService.page(userPage, wrapper);
//4.获取分页信息
System.out.println(page.getRecords());//记录内容
System.out.println(page.getPages());//总页数
System.out.println(page.getTotal());//当前查询到的记录数量
}
7、mp自动填充字段
应用场景:插入或者更新数据时,希望有些字段可以自动填充数据,比如密码、version等。例如:初始注册的用户,密码默认都是123456
怎么用?【@TableField的fill属性+配置】
【1】在需要pojo类中,需要自动填充的字段上添加注解:
@TableField并设置属性fill,fill本质是一个枚举四种权限————
DEFAULT,默认不处理
INSERT,插入时填充字段
UPDATE,更新时填充字段
INSERT_UPDATE,插入和更新时填充字段【常用!】
【2】编写配置类,实现MetaObjectHandler接口
//插入时,自动填充
@Test
public void testQueryUesrById01() {
User user = User.builder().age(18)
.email("aa@itheima.com")
.name("小明2")
.password("1234")
.age(18)
.build();
userMapper.insert(user);
}
//更新时,自动填充
@Test
public void testQueryUesrById02() {
User user = User.builder().age(18)
.email("aa@itheima.com")
.name("小明2222222")
.age(18)
.id(39L)
.build();
userMapper.updateById(user);
}
8、mp代码生成器
两种方式:
idea插件【Mybatis】 或
代码脚本:https://gitee.com/jitheima/mp_generator.git 【推荐,自由度高,泛用性广】



