目录
1 、Mybatis-Plus简介
2 、快速入门
2.1、 创建数据库及表
2.2 工程搭建
2.2.1 创建springBoot工程
2.2.2 导入依赖
2.2.3 配置application.yml
2.2.4 启动类
2.2.4 编写pojo
2.2.5 编写mapper接口和配置文件
2.2.6 编写测试用例,加入junit的依赖,测试类不能使用Test类名,测试类的包目录和启动类的路径一致
3 通用CRUD
3.1插入操作
3.1.1、方法定义:
3.1.2、测试用例:
3.1.4、@TableField
3.2、更新操作
3.2.1、根据id更新
3.2.2、根据条件更新
3.3、删除操作
3.3.1、deleteById
3.3.2、deleteByMap
3.3.3、delete
3.3.4、deleteBatchIds
3.4、查询操作
3.4.1、selectById单个查询
3.4.2、selectBatchIds 批量查询
3.4.3、selectOne 根据条件查询一条数据
3.4.4、selectCount 根据条件,查询总条数
3.4.5、selectList 根据条件查询全部记录
3.4.6、selectPage 根据条件查询全部并分页
3.5、SQL注入的原理
4、配置
4.1、基本配置
4.1.1、confifigLocation
4.1.2、mapperLocations
4.1.3、typeAliasesPackage
4.2、进阶配置
4.2.1、mapUnderscoreToCamelCase 是否自动开启驼峰命名映射
4.3、DB 相关策略配置
4.3.1、idType
4.3.2、tablePrefifix
5、条件构造器
5.1、allEq
5.2、基本比较操作
5.3、模糊查询
5.4、排序
5.5、逻辑查询
5.6、select
5.7、lambda
6、Mybatisplus的service的封装
6.1、com.baomidou.mybatisplus.extension.service.IService接口
6. 2、com.baomidou.mybatisplus.extension.service.impl.ServiceImpl类
6.3、测试用例
6.3.1、 自定义业务层接口,继承IService
6.3.2、自定义业务层实现类,继承ServiceImpl:
6.3.3、测试类:
7、代码生成器
7.1、 代码生成说明
7.2、 代码生成
7.2.1、导入依赖
7.2.2、代码生成是基于模板做的,这里采用的freemark模块来生成,把template文件夹放到resources
7.2.3、编写生产代码的类CodeGenerator
7.2.4、生成代码
8、MybatisX 快速开发插件
1 、Mybatis-Plus简介
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。该框架由baomidou(苞米豆)组织开发并且开源的。官网:mybatis.plus 或 https://mp.baomidou.com/,码云地址:baomidou: 苞米豆,为提高生产率而生!
2 、快速入门
2.1、 创建数据库及表
-- 创建测试表
CREATE TABLE `tb_user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`user_name` varchar(20) NOT NULL COMMENT '用户名',
`password` varchar(20) NOT NULL COMMENT '密码',
`name` varchar(30) DEFAULT NULL COMMENT '姓名',
`age` int(11) DEFAULT NULL COMMENT '年龄',
`email` varchar(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- 插入测试数据
INSERT INTO `tb_user` (`id`, `user_name`, `password`, `name`, `age`, `email`) VALUES ('1', 'zhangsan', '123456', '张三', '18', 'test1@chen.cn');
INSERT INTO `tb_user` (`id`, `user_name`, `password`, `name`, `age`, `email`) VALUES ('2', 'lisi', '123456', '李四', '20', 'test2@chen.cn');
INSERT INTO `tb_user` (`id`, `user_name`, `password`, `name`, `age`, `email`) VALUES ('3', 'wangwu', '123456', '王五', '28', 'test3@chen.cn');
INSERT INTO `tb_user` (`id`, `user_name`, `password`, `name`, `age`, `email`) VALUES ('4', 'zhaoliu', '123456', '赵六', '21', 'test4@chen.cn');
INSERT INTO `tb_user` (`id`, `user_name`, `password`, `name`, `age`, `email`) VALUES ('5', 'sunqi', '123456', '孙七', '24', 'test5@chen.cn');
2.2 工程搭建
2.2.1 创建springBoot工程
2.2.2 导入依赖
org.springframework.boot
spring-boot-starter-parent
2.1.5.RELEASE
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-logging
org.springframework.boot
spring-boot-starter-test
test
org.projectlombok
lombok
true
com.baomidou
mybatis-plus-boot-starter
3.1.1
mysql
mysql-connector-java
5.1.47
org.slf4j
slf4j-log4j12
com.baomidou
mybatis-plus-generator
3.1.2
org.springframework.boot
spring-boot-maven-plugin
log4j.properties:
log4j.rootLogger=DEBUG,A1 log4j.appender.A1=org.apache.log4j.ConsoleAppender log4j.appender.A1.layout=org.apache.log4j.PatternLayout log4j.appender.A1.layout.ConversionPattern=[%t] [%c]-[%p] %m%n
2.2.3 配置application.yml
spring:
application:
name: mybatisplusspringboot
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: 123
# 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
mybatis-plus:
mapper-locations: classpath*:mybatis
@SpringBootApplication
@MapperScan(basePackages = "com.chen.mp.mapper")//用于扫描mapper接口文件
public class MpApplication {
public static void main(String[] args) {
System.out.println("ss");
SpringApplication.run(MpApplication.class,args);
}
}
2.2.4 编写pojo
package com.chen.mp.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data//使用lombok完成get和set
@TableName("tb_user")//对应数据库的表名
public class User {
@TableId(value = "ID",type = IdType.AUTO)
private Long id;
@TableField("USER_NAME")//此属性名称和数据库中字段名称不符合,所以显示的映射
private String userName;//此属性名称和数据库中字段名称相同,所以隐式的映射
private String password;
private String name;
private Integer age;
private String email;
}
2.2.5 编写mapper接口和配置文件
package com.chen.mp.mapper;
import com.baomidou.mybatisplus.core.mapper.baseMapper;
import com.chen.mp.pojo.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends baseMapper {
}
package com.chen.mp.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data//使用lombok完成get和set
@TableName("tb_user")//对应数据库的表名
public class User {
@TableId(value = "ID",type = IdType.AUTO)
private Long id;
@TableField("USER_NAME")//此属性名称和数据库中字段名称不符合,所以显示的映射
private String userName;//此属性名称和数据库中字段名称相同,所以隐式的映射
private String password;
private String name;
private Integer age;
private String email;
}
2.2.5 编写mapper接口和配置文件
package com.chen.mp.mapper;
import com.baomidou.mybatisplus.core.mapper.baseMapper;
import com.chen.mp.pojo.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends baseMapper {
}
在resources目录下新建一个文件夹mybatis,专门存放mapper配置文件,用于扩展自定义的sql
2.2.6 编写测试用例,加入junit的依赖,测试类不能使用Test类名,测试类的包目录和启动类的路径一致
package com.chen;
import com.chen.mp.mapper.UserMapper;
import com.chen.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.SpringRunner;
import java.util.List;
@RunWith(SpringRunner.class)//使用springrunner运行器
@SpringBootTest(classes = MpApplication.class)//启用springboot测试,加载Springboot配置文件
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
//查询所有
@Test
public void testSelectAll(){
List userList = userMapper.selectList(null);
System.out.println(userList);
}
//查询一个
@Test
public void testSelectOne(){
User user = userMapper.selectById(1);
System.out.println(user);
}
//保存
@Test
public void testSave(){
User user = new User();
user.setUserName("xiaozhao");
user.setAge(40);
user.setPassword("xiaozhao");
user.setName("小赵");
user.setEmail("xiaozhao@email.com");
userMapper.insert(user);
}
//修改
@Test
public void testUpdate(){
User user = new User();
user.setId(1228242594492923909l);
user.setName("老赵");
userMapper.updateById(user);
}
//删除
@Test
public void testDelete(){
int i = userMapper.deleteById(1228242594492923909l);
}
}
3 通用CRUD
完成了demo的搭建,接下来查看我们继承的baseMapper中的单表操作
3.1插入操作
3.1.1、方法定义:
3.1.2、测试用例:
@Autowired private UserMapper userMapper;
@Test
public void testInsert(){
User user = new User();
user.setAge(20);
user.setEmail("test@itcast.cn");
user.setName("曹操");
user.setUserName("caocao");
user.setPassword("123456");
//返回的result是受影响的行数,并不是自增后的id
int result = this.userMapper.insert(user);
System.out.println("result = " + result);
System.out.println(user.getId()); //自增后的id会回填到对象中
如何设置id的生成策略 ,MP支持的id策略(查看IdType类):
package com.baomidou.mybatisplus.annotation;
public enum IdType {
AUTO(0),
NONE(1),
INPUT(2),
ID_WORKER(3),
UUID(4),
ID_WORKER_STR(5);
private final int key;
private IdType(int key) {
this.key = key;
}
public int getKey() {
return this.key;
}
}
3.1.4、@TableField
在MP中通过@TableField注解可以指定字段的一些属性,常常解决的问题有2个:
- 对象中的属性名和字段名不一致的问题(非驼峰)
- 对象中的属性字段在表中不存在的问题
3.2、更新操作
在MP中,更新操作有2种,一种是根据id更新,另一种是根据条件更新。
3.2.1、根据id更新
方法定义:
测试:
@Autowired
private UserMapper userMapper;
@Test
public void testUpdateById() {
User user = new User();
user.setId(6L); //主键
user.setAge(21); //更新的字段
//根据id更新,更新不为null的字段
userMapper.updateById(user); }
3.2.2、根据条件更新
方法定义:
测试:
第一种:通过QueryMapper对象
@Autowired private UserMapper userMapper;
@Test
public void testUpdate() {
User user = new User();
user.setAge(22); //更新的字段
QueryWrapper wrapper = new QueryWrapper<>();
//更新的条件
wrapper.eq("id", 6);
//执行更新操作
int result = this.userMapper.update(user, wrapper);
System.out.println("result = " + result);
第二种: UpdateWrapper对象
@Test
public void testUpdate() {
//更新的条件以及字段
UpdateWrapper wrapper = new UpdateWrapper<>();
wrapper.eq("id", 6).set("age", 23);
//执行更新操作
int result = this.userMapper.update(null, wrapper);
System.out.println("result = " + result);
}
3.3、删除操作
3.3.1、deleteById
方法定义:
测试用例:
@Autowired
private UserMapper userMapper;
@Test
public void testDeleteById() {
//执行删除操作
int result = this.userMapper.deleteById(6L);
System.out.println("result = " + result);
}
3.3.2、deleteByMap
方法定义:
测试:
@Autowired
private UserMapper userMapper;
@Test
public void testDeleteByMap() {
Map columnMap = new HashMap<>();
columnMap.put("age",20);
columnMap.put("name","张三");
//将columnMap中的元素设置为删除的条件,多个之间为and关系
//执行的sql语句:DELETE FROM tb_user WHERe name = ? AND age = ?
int result = this.userMapper.deleteByMap(columnMap);
System.out.println("result = " + result);
}
3.3.3、delete
方法定义:
测试:
@Test
public void testDeleteByMap() {
User user = new User();
user.setAge(20);
user.setName("张三"); //将实体对象进行包装,包装为操作条件
QueryWrapper wrapper = new QueryWrapper<>(user);
int result = this.userMapper.delete(wrapper);
System.out.println("result = " + result);
}
3.3.4、deleteBatchIds
方法定义:
测试:
@Test
public void testDeleteByMap() {
//根据id集合批量删除
int result = this.userMapper.deleteBatchIds(Arrays.asList(1L,10L,20L)); System.out.println("result = " + result);
}
3.4、查询操作
MP提供了多种查询操作,包括根据id查询、批量查询、查询单条数据、查询列表、分页查询等操作。
3.4.1、selectById单个查询
方法定义:
测试:
@Autowired
private UserMapper userMapper;
@Test
public void testSelectById() {
//根据id查询数据
User user = this.userMapper.selectById(2L);
System.out.println("result = " + user);
}
3.4.2、selectBatchIds 批量查询
方法定义:
测试:
@Autowired
private UserMapper userMapper;
@Test
public void testSelectBatchIds() {
//根据id集合批量查询
List users = this.userMapper.selectBatchIds(Arrays.asList(2L, 3L, 10L));
for (User user : users) {
System.out.println(user);
}
}
3.4.3、selectOne 根据条件查询一条数据
方法定义:
测试:
@Test
public void testSelectOne() {
QueryWrapper wrapper = new QueryWrapper();
wrapper.eq("name", "李四");
//根据条件查询一条数据,如果结果超过一条会报错
User user = this.userMapper.selectOne(wrapper);
System.out.println(user);
}
3.4.4、selectCount 根据条件,查询总条数
方法定义:
测试:
@Test
public void testSelectCount() {
QueryWrapper wrapper = new QueryWrapper();
//年龄大于23岁
wrapper.gt("age", 23);
//根据条件查询数据条数
Integer count = this.userMapper.selectCount(wrapper);
System.out.println("count = " + count);
}
3.4.5、selectList 根据条件查询全部记录
方法定义:
测试:
@Test
public void testSelectList() {
QueryWrapper wrapper = new QueryWrapper();
//年龄大于23岁
wrapper.gt("age", 23);
//根据条件查询数据
List users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println("user = " + user);
}
}
3.4.6、selectPage 根据条件查询全部并分页
配置分页插件(自定义一个类):
package com.chen.mp.config;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Bean;
@Configurable
@MapperScan("com.chen.mp.mapper") //设置mapper接口的扫描包
public class MybatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor(); }
}
方法定义:
测试:
@Test
public void testSelectPage() {
QueryWrapper wrapper = new QueryWrapper();
//年龄大于20岁
wrapper.gt("age", 20);
//参数:当前页,每页条数
Page page = new Page<>(1,1);
//根据条件查询数据
IPage iPage = this.userMapper.selectPage(page, wrapper);
System.out.println("数据总条数:" + iPage.getTotal());
System.out.println("总页数:" + iPage.getPages());
List users = iPage.getRecords();
for (User user : users) {
System.out.println("user = " + user);
}
}
3.5、SQL注入的原理 在 MP 中, ISqlInjector 负责 SQL 的注入工作,它是一个接口, AbstractSqlInjector 是它的实现类,实现关系如下:
在AbstractSqlInjector中,主要是由inspectInject()方法进行注入的,如下:
@Override
public void inspectInject(
MapperBuilderAssistant builderAssistant, Class>
mapperClass) {
Class> modelClass = extractModelClass(mapperClass);
if (modelClass != null) {
String className = mapperClass.toString();
Set mapperRegistryCache = GlobalConfigUtils.getMapperRegistryCache(builderAssistant.getConfiguration());
if (!mapperRegistryCache.contains(className)) {
List methodList = this.getMethodList();
if (CollectionUtils.isNotEmpty(methodList)) {
TableInfo tableInfo = TableInfoHelper.initTableInfo(builderAssistant, modelClass);
// 循环注入自定义方法
methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass, tableInfo));
} else {
logger.debug(mapperClass.toString() + ", No effective injection method was found.");
}
mapperRegistryCache.add(className);
}
}
}
在实现方法中,
methodList.forEach(m
-
> m.inject(builderAssistant, mapperClass, modelClass,
tableInfo))
;
是关键,循环遍历方法,进行注入。
最终调用抽象方法
injectMappedStatement
进行真正的注入:
public abstract MappedStatement injectMappedStatement(Class> mapperClass, Class > modelClass, TableInfo tableInfo);查看该方法的实现:
以SelectById为例查看:
public class SelectById extends AbstractMethod {
@Override public MappedStatement injectMappedStatement(Class> mapperClass, Class> modelClass, TableInfo tableInfo) {
SqlMethod sqlMethod = SqlMethod.LOGIC_SELECT_BY_ID;
SqlSource sqlSource = new RawSqlSource(configuration, String.format(sqlMethod.getSql(),
sqlSelectColumns(tableInfo, false),
tableInfo.getTableName(),
tableInfo.getKeyColumn(),
tableInfo.getKeyProperty(),
tableInfo.getLogicDeleteSql(true, false)), Object.class);
return this.addSelectMappedStatement(mapperClass, sqlMethod.getMethod(), sqlSource, modelClass, tableInfo);
}
}
可以看到,生成了
SqlSource
对象,再将
SQL
通过
addSelectMappedStatement方法添加到
MappedStatement
中。
4、配置
在 MP 中有大量的配置,其中有一部分是 Mybatis 原生的配置,另一部分是 MP 的配置,详情: https://mybatis.plus/c onfifig/ 下面我们对常用的配置做讲解4.1、基本配置
4.1.1、confifigLocation
MyBatis
配置文件位置,如果您有单独的
MyBatis
配置,请将其路径配置到
confifigLocation
中。
MyBatis
Confifiguration
的具体内容请参考
MyBatis
官方文档
Spring Boot
:
mybatis-plus.config-location = classpath:mybatis-config.xml
Spring MVC:
4.1.2、mapperLocations
Maven 多模块项目的扫描路径需以 classpath*: 开头 (即加载多个 jar 包下的 XML 文件)
MyBatis Mapper
所对应的
XML
文件位置,如果您在
Mapper
中有自定义方法(
XML
中有自定义实现),需要进行
该配置,告诉
Mapper
所对应的
XML
文件位置。
Spring Boot
:
Maven 多模块项目的扫描路径需以 classpath*: 开头 (即加载多个 jar 包下的 XML 文件)
mybatis-plus.mapper-locations = classpath*:mybatis
public class CodeGenerator {
// TODO 修改服务名以及数据表名
private static final String SERVICE_NAME = "mp";
private static final String DATA_SOURCE_USER_NAME = "root";
private static final String DATA_SOURCE_PASSWORD = "123";
private static final String[] TABLE_NAMES = new String[]{
"tb_user"
};
// TODO 默认生成entity,需要生成DTO修改此变量
// 一般情况下要先生成 DTO类 然后修改此参数再生成 PO 类。
private static final Boolean IS_DTO = false;
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 选择 freemarker 引擎,默认 Velocity
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
// 全局配置
GlobalConfig gc = new GlobalConfig();
gc.setFileOverride(true);
gc.setOutputDir(System.getProperty("user.dir") + "/src/main/java");
gc.setAuthor("chenfan");
gc.setOpen(false);
gc.setSwagger2(false);
gc.setServiceName("%sService");
gc.setbaseResultMap(true);
gc.setbaseColumnList(true);
if (IS_DTO) {
gc.setSwagger2(true);
gc.setEntityName("%sDTO");
}
mpg.setGlobalConfig(gc);
// 数据库配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setDbType(DbType.MYSQL);
dsc.setUrl("jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&useSSL=false&characterEncoding=utf8");
dsc.setDriverName("com.mysql.jdbc.Driver");
dsc.setUsername(DATA_SOURCE_USER_NAME);
dsc.setPassword(DATA_SOURCE_PASSWORD);
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName(SERVICE_NAME);
pc.setParent("com.chen");
pc.setServiceImpl("service.impl");
pc.setXml("mapper");
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
List focList = new ArrayList<>();
focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输入文件名称
return System.getProperty("user.dir") + "/src/main/resources/mapper/" +
tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
// 设置模板
TemplateConfig tc = new TemplateConfig();
mpg.setTemplate(tc);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
strategy.setInclude(TABLE_NAMES);
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix(pc.getModuleName() + "_");
// Boolean类型字段是否移除is前缀处理
strategy.setEntityBooleanColumnRemoveIsPrefix(true);
strategy.setRestControllerStyle(true);
mpg.setStrategy(strategy);
mpg.execute();
}
}
参数说明:
7.2.4、生成代码
执行CodeGenerator类中的main方法,就可以生成文件
8、MybatisX 快速开发插件
MybatisX 是一款基于 IDEA 的快速开发插件,为效率而生。
安装方法:打开 IDEA,进入 File -> Settings -> Plugins ->输入 mybatisx 搜索并安装。
功能:
-
Java 与 XML 调回跳转
-
Mapper 方法自动生成 XML



