MyBatis-Plus简要概述
一.MyBatis-Plus简介
[MyBatis-Plus (opens new window)](https://github.com/baomidou/mybatis-plus)(简称 MP)是一个 [MyBatis (opens new window)](https://www.mybatis.org/mybatis-3/)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
1.阅读前置
MyBatis 、 Spring Boot 、 Maven
2.特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
- 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
- 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
- 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
- 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
- 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
- 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
- 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
- 内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
- 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
3.支持数据库
任何能使用
MyBatis
进行 CRUD, 并且支持标准 SQL 的数据库
- MySQL,Oracle,DB2,H2,HSQL,SQLite,PostgreSQL,SQLServer,Phoenix,Gauss ,ClickHouse,Sybase,OceanBase,Firebird,Cubrid,Goldilocks,csiidb,informix,TDengine,redshift
- 达梦数据库,虚谷数据库,人大金仓数据库,南大通用(华库)数据库,南大通用数据库,神通数据库,瀚高数据库,优炫数据库,星瑞格数据库
4.框架结构
二.快速开始
1.初始化工程
创建一个空的 Spring Boot 工程
2.添加依赖
- 引入 Spring Boot Starter 父工程:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5+ 版本</version>
<relativePath/>
</parent>
- 引入
spring-boot-starter
、spring-boot-starter-test
、mybatis-plus-boot-starter
、h2
依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>最新版本</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
3.配置
- 在
application.yml
配置文件中添加数据库的相关配置:
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/gcxy_teach?serverTimezone=UTC
username: root
password: 123456
main:
banner-mode:off #关闭SpringBoot启动图标(banner)
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #打印SQL到控制台
global-config:
banner: off #关闭mybatisplus启动图标
mapper-locations: classpath:/mapper/*Mapper.xml
- 在 Spring Boot 启动类中添加
@MapperScan
注解,扫描 Mapper 文件夹:
@SpringBootApplication
@MapperScan("com.baomidou.mybatisplus.samples.quickstart.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4.代码生成器
(1)新
注意
适用版本:mybatis-plus-generator 3.5.1 及其以上版本,对历史版本不兼容!3.5.1 以下的请参考 代码生成器旧
1.基础配置
new DataSourceConfig.Builder("jdbc:mysql://127.0.0.1:3306/mybatis-plus","root","123456")
.build();
2.可选配置
// 使用SQL查询的方式生成代码,属于旧的代码生成方式,通用性不是好,老的代码可以继续使用,适配数据库需要完成dbQuery和typeConvert的扩展,后期不再维护这种方式
new DataSourceConfig.Builder("jdbc:mysql://127.0.0.1:3306/mybatis-plus","root","123456")
.dbQuery(new MySqlQuery())
.schema("mybatis-plus")
.typeConvert(new MySqlTypeConvert())
.keyWordsHandler(new MySqlKeyWordsHandler())
.databaseQueryClass(SQLQuery.class)
.build();
// 使用元数据查询的方式生成代码,默认已经根据jdbcType来适配java类型,支持使用typeConvertHandler来转换需要映射的类型映射
new DataSourceConfig.Builder("jdbc:mysql://127.0.0.1:3306/mybatis-plus","root","123456")
.schema("mybatis-plus")
.keyWordsHandler(new MySqlKeyWordsHandler())
.build();
3.全局配置
new GlobalConfig.Builder()
.fileOverride()
.outputDir("/opt/baomidou")
.author("baomidou")
.enableKotlin()
.enableSwagger()
.dateType(DateType.TIME_PACK)
.commentDate("yyyy-MM-dd")
.build();
4.包配置
new PackageConfig.Builder()
.parent("com.baomidou.mybatisplus.samples.generator")
.moduleName("sys")
.entity("po")
.service("service")
.serviceImpl("service.impl")
.mapper("mapper")
.xml("mapper.xml")
.controller("controller")
.other("other")
.pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D://"))
.build();
5.模板配置
new TemplateConfig.Builder()
.disable(TemplateType.ENTITY)
.entity("/templates/entity.java")
.service("/templates/service.java")
.serviceImpl("/templates/serviceImpl.java")
.mapper("/templates/mapper.java")
.mapperXml("/templates/mapper.xml")
.controller("/templates/controller.java")
.build();
6.注入配置
new InjectionConfig.Builder()
.beforeOutputFile((tableInfo, objectMap) -> {
System.out.println("tableInfo: " + tableInfo.getEntityName() + " objectMap: " + objectMap.size());
})
.customMap(Collections.singletonMap("test", "baomidou"))
.customFile(Collections.singletonMap("test.txt", "/templates/test.vm"))
.build();
7.策略配置
new StrategyConfig.Builder()
.enableCapitalMode()
.enableSkipView()
.disableSqlFilter()
.likeTable(new LikeTable("USER"))
.addInclude("t_simple")
.addTablePrefix("t_", "c_")
.addFieldSuffix("_flag")
.build();
(2)旧
public class CodeGenerator {
public static void main(String[] args) {
String url="jdbc:mysql://localhost:3306/gcxy_teach?serverTimezone=UTC";
String username="root";
String password="123456";
String author="zhangr132";
String module="";//表示项目的模块名称
String outPath=System.getProperty("user.dir")+"/"+module+"/src/main/java";//输出目录
String parent="com.gcxy";//父包的名称
String moduleName="";//父包模块名
String entity="entity";//Entity 实体类包名
String mapper="mapper";//Mapper 包名
String service="service";//Service 包名
String serviceImpl="service.Impl";//Service Impl 包名
String controller="controller";//Controller 包名*/
String mapperXml="mapper.xml";//Mapper XML 包名
List<String> tables=new ArrayList<>();
tables.add("account");
tables.add("phone");
tables.add("dep");
tables.add("stu");
FastAutoGenerator.create(url, username, password)
//全局配置
.globalConfig(builder -> {
builder.author(author) // 设置作者
// .enableSwagger() // 开启 swagger 模式
.fileOverride() // 覆盖已生成文件
.outputDir(outPath) // 指定输出目录
.disableOpenDir() //生成之后不打开目录
.dateType(DateType.ONLY_DATE) //定义生成的实体类中日期类型 DateType.ONLY_DATE 默认值: DateType.TIME_PACK
.commentDate("yyyy-MM-dd");//注释日期
})
//包配置
.packageConfig(builder -> {
builder.parent(parent) // 设置父包名
.moduleName(moduleName) // 设置父包模块名
.entity(entity)
.mapper(mapper)
.service(service)
.serviceImpl(serviceImpl)
.controller(controller)
.xml(mapperXml);
// .pathInfo(Collections.singletonMap(OutputFile.xml, "D://")); // 设置mapperXml生成路径
})
//模板配置
//策略配置
.strategyConfig(builder -> {
builder.addInclude(tables) // 设置需要生成的表名
// .addTablePrefix("t_", "c_"); // 设置过滤表前缀
.entityBuilder() //开启生成实体类
.enableLombok() //开启lombok模型
.mapperBuilder() //开启生成mapper
.superClass(BaseMapper.class)//设置父类
.enableMapperAnnotation() //开启 @Mapper 注解
.formatMapperFileName("%sMapper")//格式化mapper名称
.formatXmlFileName("%sMapper")//格式化 xml 实现类文件名称
//开启生成service及impl
.serviceBuilder()
.formatServiceFileName("%sService")//格式化 service 接口文件名称
.formatServiceImplFileName("%sServiceImpl")//格式化 service 实现类文件名称
//开启生成controller
.controllerBuilder()
// 映射路径使用连字符格式,而不是驼峰
//.enableHyphenStyle()
.formatFileName("%sController")//格式化文件名称
.enableRestStyle();
})
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
.execute();
}
}
5.CRUD接口
(1)增
List<Phone> phoneList = phoneMapper.selectList(null);
System.out.println(phoneList);
phoneList.forEach(phone -> System.out.println(phone.toString()));
// 插入数据
/**
使用mapper层查询数据 在mapper中只封装了insert()方法
*/
User user = new User();
user.setAge(10);
user.setGender(1);
user.setName("xiaoming");
userMapper.insert(user);
Long id = user.getId();
System.out.println("id:" + id);
// 这service中封装的插入方法 save
boolean isSuccess = userService.save(user);
//伪批量插入:saveBatch()
List<User> userList=new ArrayList<>();
for(int i=1;i<5;i++){
User user1=new User();
user1.setAge(10+i);
user1.setGender(1+i);
user1.setName("xiaoming"+1);
userList.add(user1)
}
boolean isSuccess=userService.saveBatch(userList);
System.out.println("返回结果:"+isSuccess);
(2)删
//Mapper层删除功能
//根据主键id删除数据(直接传id)
int count=userMapper.deleteById(9L);
System.out.println("删除了"+count+"条数据");
//根据主键id删除(传实体类)
User user = new User();
user.setId(8L);
int count = userMapper.deleteById(user);
System.out.println("删除了:"+ count);
//根据主键id批量删除
List<Long> ids =new ArrayList<>();
ids.add(1L);
ids.add(2L);
// delete from user where id in(1,2)
userMapper.deleteBatchIds(ids);
//通过构造Wrapper构造器删除
QueryWrapper wrapper=new QueryWrapper<>();
wrapper.eq("name","xiaoming1");
wrapper.eq("age",11);
// delete from user where (name="xiaoming" and age=11)
userMapper.delete(wrapper);
//lambda表达式
userMapper.delete(new QueryWrapper<>()
.lambda()
.eq(User::getName,"xiaoming1")
.eq(User::getAge,11)
);
//使用map设置条件删除
Map<String, Object> col=new HashMap<>();
col.put("name","xiaoming2");
col.put("age",12);
int count =userMapper.deleteByMap(col);
System.out.println("删除了"+count+"条数据");
(3)改
//更新数据
//mapper层
User user=User.builder()
.name("xiaoming")
.id(5L)
.gender(0)
.build();
int count =userMapper.updateById(user);
System.out.println("更新了"+count+"条数据");
//通过wrapper进行更新
User user=User.builder()
.name("hahah")
.gender("1")
.build();
UpdateWrapper<User> userUpdateWrapper=new UpdateWrapper<>();
userUpdateWrapper.eq("age",13);
int count= UpdateWrapper.update(user,userUpdateWrapper);
//service层
UpdateWrapper<User> userUpdateWrapper=new UpdateWrapper<>();
userUpdateWrapper.set("name","xixixi");
userUpdateWrapper.set("id","13");
userService.update(userUpdateWrapper);
(4)查
//查询数据
//mapper层‘
//根据id查询
User user=userMapper.selectById(5L);
System.out.println(user.toString());
//通过构造wrapper条件查询一条数据
QueryWrapper<User> queryWrapper=new QueryWrapper<>();
//设置查询字段:仅查询name,id字段
queryWrapper.select("id","name");
//添加查询条件
queryWrapper.eq("id",5L);
User user1=userMapper.selectOne(queryWrapper);
System.out.println(user1.toString());
//根据id批量查询
List<User> userList=userMapper.selectBatchIds(Arrays.asList(5L,6L,7L));
//通过wrapper组装查询条件,查询全部数据
QueryWrapper<User> queryWrapper=new QueryWrapper<>();
//设置查询字段:仅查询name id字段
queryWrapper.select("id","name");
// 添加查询条件
queryWrapper.eq("age",30);
List<User> users = userMapper.selectList(queryWrapper); // 查询全部数据
// 根据columnMap设置查询条件
Map<String,Object> colMap = new HashMap<>();
colMap.put("name","xixix");
colMap.put("age",13);
// select * from user where name="xixix" and age=13;
List<User> userList1 = userMapper.selectByMap(colMap); // 使用map构造查询
//根据wrapper条件,查询记录总数
QueryWrapper<User> queryWrapper=new QueryWrapper<>();
queryWrapper.eq("name","xixi").eq("age",13);
long count=userMapper.selectCount(queryWrapper); //获取总数量
//service
User user= userService.getById(5L); //根据id获取数据
//通过wrapper条件查询一条数据,当结果出现多条数据是会抛出异常
QueryWrapper<User> queryWrapper=new QueryWrapper<>();
queryWrapper.eq("name","xixi").eq("id",5L);
//select * from user where id=5 and name="xixi"
User user1=userService.getOne(queryWrapper);
//通过list开头的方法来查询多条数据
//条件查询
QueryWrapper<User> queryWrapper=new QueryWrapper<>();
queryWrapper.eq("name","xixi").eq("id",5L);
//select * from user where id=5 and namei="xixi"
List<User> users=userService.list(queryWrapper);
//根据id列表查询数据
//select *form user where id in(5,6)
List<User> userList=userService.listByIds(Arrays.asList(5L,6L));
//通过map构造查询条件
Map<String,Object> cloMap=new HashMap<>();
cloMap.put("name","xixi");
cloMap.put("age",13);
//select *from user where age=13 and name="xixi"
List<User> userList1=userService.listByMap(cloMap);
//获取查询总数
QueryWrapper<User> queryWrapper1=new QueryWrapper<>();
queryWrapper1.eq("name","xixi").eq("id",5L);
userService.count(queryWrapper1); // 获取插叙总数
//mapper分层查询
QueryWrapper<User> queryWrapper=new QueryWrapper<>();
queryWrapper.eq("age",30);
Page<User> page=new Page<>(2,10);
//多表管理查询
//需求:假设前端需要展示数据:订单号、商品名称、商品价格、下单用户名、下单用户年龄、性别
//sql:select o.order_id,o.user_id,o.goods_name,o.goods_price,u.name,u.age,u.gender from t_order as o left join t_user as u on o.user_id=u.id
List<OrderView> orderViews=userMapper.selectOrders();
orderViews.forEach(System.out::println);
//关联分页查询
//查询第一页,每页数据显示10条
Page<OrderView> page=new Page<>(1,10);
//手动关闭sql优化,否则查询总数的时候只会查询主表
page.setOptimizeCountSql(false);
//组装查询条件age=30
QueryWrapper<OrderView> queryWrapper=new QueryWrapper<>();
queryWrapper.eq("age",30);
IPage<OrderView> page1=userMapper.selectOrderPage(page,queryWrapper);
System.out.println("总记录数:"+page1.getTotal());
System.out.println("总共页数:"+page1.getPages());
System.out.println("当前页码:"+page1.getCurrent());
System.out.println("当前查询数据:"+page1.getRecords());
(5)更新
// 批量保存或者更新
List<User> userList = new ArrayList<>();
for (int i =3;i<10;i++){
User user1 = new User();
user1.setAge(10+ i);
user1.setGender(1 + i);
user1.setName("xiaoming" + i);
userList.add(user1);
}
boolean isSuccess = userService.saveOrUpdateBatch(userList);
System.out.println("返回结果:"+isSuccess );
分页插件
配置方法
@Configuration
@MapperScan("com.gcxy.mapper")
public class MybatisPlusConfig {
/**
* 添加分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//如果配置多个插件,切记分页最后添加
//interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 如果有多数据源可以不配具体类型 否则都建议配上具体的DbType
return interceptor;
}
}
阅读推荐
- SpringBoot简要概述
- 简介 | MyBatis-Plus (baomidou.com)
- Maven – Welcome to Apache Maven
- Spring Boot 中文文档 (springdoc.cn)