了解Mybatis-Plus

整合Mybatis-Plus
对于Mybatis整合MP有常常有三种用法,分别是Mybatis+MP、Spring+Mybatis+MP、Spring Boot+Mybatis+MP。
Spring+Mybatis+MP
额外导入的jar包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>itcast-mybatis-plus</artifactId>
<groupId>cn.itcast.mp</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>itcast-mybatis-plus-spring</artifactId>
<properties>
<spring.version>5.1.6.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
</project>
编写applicationContext.xml(<!--这里使用MP提供的sqlSessionFactory,完成了Spring与MP的整合--> )
<!--这里使用MP提供的sqlSessionFactory,完成了Spring与MP的整合-->
<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="globalConfig">
<bean class="com.baomidou.mybatisplus.core.config.GlobalConfig">
<property name="dbConfig">
<bean class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig">
<property name="idType" value="AUTO"/>
</bean>
</property>
</bean>
</property>
</bean>
<!--扫描mapper接口,使用的依然是Mybatis原生的扫描器-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.itcast.mp.simple.mapper"/>
</bean>
user接口需要继承BaseMapper<User>
package cn.itcast.mp.simple.mapper;
import cn.itcast.mp.simple.pojo.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface UserMapper extends BaseMapper<User> {
}
测试用例(List<User> users = this.userMapper.selectList(null); )
package cn.itcast.mp.simple;
import cn.itcast.mp.simple.mapper.UserMapper;
import cn.itcast.mp.simple.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class TestMybatisSpring {
@Autowired
private UserMapper userMapper;
@Test
public void testSelectList(){
List<User> users = this.userMapper.selectList(null);
for (User user : users) {
System.out.println(user);
}
}
}
Spring Boot+Mybatis+MP
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
</parent>
<groupId>cn.itcast.mp</groupId>
<artifactId>itcast-mp-springboot</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--简化代码的工具包-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--mybatis-plus的springboot支持-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.1</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
</dependencies>
<!-- <build>-->
<!-- <plugins>-->
<!-- <plugin>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-maven-plugin</artifactId>-->
<!-- <version>1.5.4</version>-->
<!-- </plugin>-->
<!-- </plugins>-->
<!-- </build>-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.0.1.RELEASE</version>
</plugin>
</plugins>
</build>
</project>
user接口需要继承BaseMapper<User>
package cn.itcast.mp.simple.mapper;
import cn.itcast.mp.simple.pojo.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface UserMapper extends BaseMapper<User> {
}
MyApplication
package cn.itcast.mp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
测试用例
package cn.itcast.mp;
import cn.itcast.mp.mapper.UserMapper;
import cn.itcast.mp.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class TestMybatisSpringBoot {
@Autowired
private UserMapper userMapper;
@Test
public void testSelectList(){
List<User> users = this.userMapper.selectList(null);
for (User user : users) {
System.out.println(user);
}
}
}
通用CRUD
/**
* Mapper 继承该接口后,无需编写 mapper.xml 文件,即可获得CRUD功能
* <p>这个 Mapper 支持 id 泛型</p>
*
* @author hubin
* @since 2016-01-23
*/
public interface BaseMapper<T> extends Mapper<T> {
/**
* 插入一条记录
*
* @param entity 实体对象
*/
int insert(T entity);
/**
* 根据 ID 删除
*
* @param id 主键ID
*/
int deleteById(Serializable id);
/**
* 根据 columnMap 条件,删除记录
*
* @param columnMap 表字段 map 对象
*/
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
/**
* 根据 entity 条件,删除记录
*
* @param wrapper 实体对象封装操作类(可以为 null)
*/
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
/**
* 删除(根据ID 批量删除)
*
* @param idList 主键ID列表(不能为 null 以及 empty)
*/
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
/**
* 根据 ID 修改
*
* @param entity 实体对象
*/
int updateById(@Param(Constants.ENTITY) T entity);
/**
* 根据 whereEntity 条件,更新记录
*
* @param entity 实体对象 (set 条件值,可以为 null)
* @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
*/
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);
/**
* 根据 ID 查询
*
* @param id 主键ID
*/
T selectById(Serializable id);
/**
* 查询(根据ID 批量查询)
*
* @param idList 主键ID列表(不能为 null 以及 empty)
*/
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
/**
* 查询(根据 columnMap 条件)
*
* @param columnMap 表字段 map 对象
*/
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
/**
* 根据 entity 条件,查询一条记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 Wrapper 条件,查询总记录数
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 entity 条件,查询全部记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 Wrapper 条件,查询全部记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 Wrapper 条件,查询全部记录
* <p>注意: 只返回第一个字段的值</p>
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 entity 条件,查询全部记录(并翻页)
*
* @param page 分页查询条件(可以为 RowBounds.DEFAULT)
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 Wrapper 条件,查询全部记录(并翻页)
*
* @param page 分页查询条件
* @param queryWrapper 实体对象封装操作类
*/
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
}
插入操作(测试时要写)
@RunWith(SpringRunner.class) @SpringBootTest
@TableId(type = IdType.AUTO)
//这是plus自带的数据库配置参数,表明数据库的id是自增长
/*
* Copyright (c) 2011-2020, baomidou (jobob@qq.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.baomidou.mybatisplus.annotation;
import lombok.Getter;
/**
* 生成ID类型枚举类
*
* @author hubin
* @since 2015-11-10
*/
@Getter
public enum IdType {
/**
* 数据库ID自增
*/
AUTO(0),
/**
* 该类型为未设置主键类型
*/
NONE(1),
/**
* 用户输入ID
* <p>该类型可以通过自己注册自动填充插件进行填充</p>
*/
INPUT(2),
/* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */
/**
* 全局唯一ID (idWorker)
*/
ID_WORKER(3),
/**
* 全局唯一ID (UUID)
*/
UUID(4),
/**
* 字符串全局唯一ID (idWorker 的字符串表示)
*/
ID_WORKER_STR(5);
private final int key;
IdType(int key) {
this.key = key;
}
}
@Test
public void testInsert() {
User user = new User();
user.setMail("2@itcast.cn");
user.setAge(301);
user.setUserName("caocao1");
user.setName("曹操1");
user.setPassword("123456");
user.setAddress("北京");
int result = this.userMapper.insert(user); //result数据库受影响的行数
System.out.println("result => " + result);
//获取自增长后的id值, 自增长后的id值会回填到user对象中 但id值会乱码,需要我们手动设置策略
System.out.println("id => " + user.getId());
}
@TableField
在MP中通过@TableField注解可以指定字段的一些属性,常常解决的问题有2个:
1、对象中的属性名和字段名不一致的问题(非驼峰)
2、对象中的属性字段在表中不存在的问题(总之是对象与表参数不匹配的问题)
@TableField(select = false) //查询时不返回该字段的值
private String password;
private String name;
private Integer age;
@TableField(value = "email") //指定数据表中字段名
private String mail;
@TableField(exist = false)
private String address; //在数据库表中是不存在的
更新操作(两种,根据id更新,根据条件更新)
/**
* 根据 ID 修改
*
* @param entity 实体对象
*/
int updateById(@Param(Constants.ENTITY) T entity);
@Test
public void testUpdateById() {
User user = new User();
user.setId(1L); //条件,根据id更新
user.setAge(19); //更新的字段
user.setPassword("666666");
int result = this.userMapper.updateById(user);
System.out.println("result => " + result);
}
根据条件更新
(使用QueryWrapper,可以直接设置条件,但必须新建user对象)
@Test
public void testUpdate() {
User user = new User();
user.setAge(20); //更新的字段
user.setPassword("8888888");
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("user_name", "zhangsan"); //匹配user_name = zhangsan 的用户数据
//根据条件做更新
int result = this.userMapper.update(user, wrapper);
System.out.println("result => " + result);
}
(使用UpdateWrapper,不仅可以直接设置条件,而且可以直接设置更新参数)
@Test
public void testUpdate2() {
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
wrapper.set("age", 21).set("password", "999999") //更新的字段
.eq("user_name", "zhangsan"); //更新的条件
//根据条件做更新
int result = this.userMapper.update(null, wrapper);
System.out.println("result => " + result);
}
删除操作
根据id删除
@Test
public void testDeleteById(){
// 根据id删除数据
int result = this.userMapper.deleteById(9L);
System.out.println("result => " + result);
}
根据字段条件删除(多条件之间是and关系)
@Test
public void testDeleteByMap(){
Map<String,Object> map = new HashMap<>();
map.put("user_name", "zhangsan");
map.put("password", "999999");
// 根据map删除数据,多条件之间是and关系
int result = this.userMapper.deleteByMap(map);
System.out.println("result => " + result);
}
根据对象条件删除(两种写法)
@Test
public void testDelete(){
//用法一:
// QueryWrapper<User> wrapper = new QueryWrapper<>();
// wrapper.eq("user_name", "caocao1")
// .eq("password", "123456");
//用法二:
User user = new User();
user.setPassword("123456");
user.setUserName("caocao");
QueryWrapper<User> wrapper = new QueryWrapper<>(user);
// 根据包装条件做删除
int result = this.userMapper.delete(wrapper);
System.out.println("result => " + result);
}
根据id做批量删除
@Test
public void testDeleteBatchIds(){
// 根据id批量删除数据
int result = this.userMapper.deleteBatchIds(Arrays.asList(10L, 11L));
System.out.println("result => " + result);
}
查询操作
根据id查询
@Test
public void testSelectById() {
User user = this.userMapper.selectById(2L);
System.out.println(user);
}
根据id批量查询
@Test
public void testSelectBatchIds(){
// 根据id批量查询数据
List<User> users = this.userMapper.selectBatchIds(Arrays.asList(2L, 3L, 4L, 100L));
for (User user : users) {
System.out.println(user);
}
}
根据对象条件查询(如果查询结果超过一条会报错)
@Test
public void testSelectOne(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
//查询条件
wrapper.eq("password", "123456");
// 查询的数据超过一条时,会抛出异常
User user = this.userMapper.selectOne(wrapper);
System.out.println(user);
}
根据条件查询数据的总记录个数
@Test
public void testSelectCount(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.gt("age", 20); // 条件:年龄大于20岁的用户
// 根据条件查询数据条数
Integer count = this.userMapper.selectCount(wrapper);
System.out.println("count => " + count);
}
根据条件查询符合数据的全部记录(返回一个List,做遍历)
@Test
public void testSelectList(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
//设置查询条件
wrapper.like("email", "itcast");
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
根据条件查询符合数据的全部记录并翻页(返回一个List,做遍历)
要实现分页,需要插件
MybatisPlusConfig.java
package cn.itcast.mp;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("cn.itcast.mp.mapper") //设置mapper接口的扫描包
public class MybatisPlusConfig {
@Bean //配置分页插件-这是重点
public PaginationInterceptor paginationInterceptor(){
return new PaginationInterceptor();
}
}
Test
// 测试分页查询
@Test
public void testSelectPage(){
Page<User> page = new Page<>(3,1); //查询第一页,查询1条数据
QueryWrapper<User> wrapper = new QueryWrapper<>();
//设置查询条件
wrapper.like("email", "itcast");
IPage<User> iPage = this.userMapper.selectPage(page, wrapper);
System.out.println("数据总条数: " + iPage.getTotal());
System.out.println("数据总页数: " + iPage.getPages());
System.out.println("当前页数: " + iPage.getCurrent());
List<User> records = iPage.getRecords();
for (User record : records) {
System.out.println(record);
}
}
Mybatis-Plus的配置

配置文件到本地的意思,即在application.properties或applicationContext.xml中配置mybatis-config.xml文件(因此这是最基本的配置)
mybatisplus已经提供了一些API即basemapper,但如果像之前的多表联合查询,还是需要我们自定义mapper.xml语句(与mapper接口配合)编写sql语句进行运行,因此就需要配置mapper.xml文件,ssm整合中也提到了,即在application.properties或applicationContext.xml中配置mapper.xml文件
给全路径起别名,前面也学过了
进阶配置

值得注意的是该配置有冲突

最好还是用mybatis-plus默认设置为true,可以有效避免user对象与数据库参数不匹配问题
DB 策略配置
@TableId(type = IdType.AUTO)
但如果有很多对象都需要这个配置,就比较麻烦了,所以进行全局设置策略,使所有实体对象满足id自增长
tablePrefix
在mp中会自动把实体对象的名称小写作为表名去跟数据库匹配,但显然不对
传统做法是@TableName("tb_user")
现在可以加前缀进行映射,比如现在这个例子的前缀就是 tb_
条件构造器(自动生成一些sql语句)
allEq
@Test
public void testAllEq(){
Map<String,Object> params = new HashMap<>();
params.put("name", "李四");
params.put("age", "20");
params.put("password", null);
QueryWrapper<User> wrapper = new QueryWrapper<>();
//SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE password IS NULL AND name = ? AND age = ?
// wrapper.allEq(params);
//SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE name = ? AND age = ?
// wrapper.allEq(params, false);
//SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE age = ?
// wrapper.allEq((k, v) -> (k.equals("age") || k.equals("id")) , params);
//SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE name = ? AND age = ?
wrapper.allEq((k, v) -> (k.equals("age") || k.equals("id") || k.equals("name")) , params);
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
mybatis-plus 基本比较操作
//SELECT id,user_name,password,name,age,email FROM tb_user WHERE password = ? AND age >= ? AND name IN (?,?,?)
wrapper.eq("password", "123456")
.ge("age", 20)
.in("name", "李四", "王五", "赵六");
mybatis-plus 模糊查询(只有部分信息 王某某)
@Test
public void testLike(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
// SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE name LIKE ?
// 参数:%五(String)
wrapper.likeLeft("name", "五");
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
mybatis-plus 排序(默认正序)
orderByAsc 正序 orderDesc 倒序
@Test
public void testOrderByAgeDesc(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
//按照年龄倒序排序
// SELECT id,user_name,name,age,email AS mail FROM tb_user ORDER BY age DESC
wrapper.orderByDesc("age");
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
mybatis-plus 逻辑查询
@Test
public void testOr(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
// SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE name = ? OR age = ?
wrapper.eq("name", "王五").or().eq("age", 21);
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
在查询时,默认查询并返回所有的字段,可以通过配置指定返回的字段
.select("id","name","age"); //指定查询的字段
@Test
public void testSelect(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
//SELECT id,name,age FROM tb_user WHERE name = ? OR age = ?
wrapper.eq("name", "王五")
.or()
.eq("age", 21)
.select("id","name","age"); //指定查询的字段
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}