MyBatis-plus讲解篇
前言
这篇博文是接着前一段时间的MyBatis-Plus详细讲解(一)续写,链接如下
链接 | 地址 |
---|---|
MyBatis-Plus详细讲解(一) | 点击进入 |
话不多说,继续干
注解
具体有如下注解
注解名 | 说明 |
---|---|
@TableName | 表名注解 |
@TableId | 主键注解 |
@TableField | 字段注解(非主键) |
@Version | 乐观锁注解 |
@EnumValue | 通枚举类注解 |
@TableLogic | 表字段逻辑处理注解 |
@KeySequence | 序列主键策略 |
@InterceptorIgnore:该注解作用于 xxMapper.java 方法之上 各属性代表对应的插件 各属性不给值则默认为 false 设置为 true 忽略拦截
SpringBoot整合MyBatis-plus快速使用
依赖
项目我这边已经有了相关测试demo,大家那就自己去创建一个吧,创建好后,依赖如下
主要依赖如下
1:SpringBoot
2:MyBatis-plus
3:SpringBoot web
4:MySQL
5:Swagger2
6:Lombok
<?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 https://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.3.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.uncletj</groupId>
<artifactId>mybatis-plus-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mybatis-plus-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--SpringBoot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--MyBatis-plus 3.4.2-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<!--springboot-web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--MySQL-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--Swagger2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.4.0</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
数据库测试表
接下来既然后端框架已经搭建好了那么数据库在创建一个吧,我就不用之前那个了,为了方便我这里直接把数据库中的测试表给出大家,直接粘贴过去就行了
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for intro
-- ----------------------------
DROP TABLE IF EXISTS `intro`;
CREATE TABLE `intro` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键id',
`name` varchar(40) COLLATE utf8_bin NOT NULL COMMENT '姓名',
`age` int NOT NULL COMMENT '年龄',
`gender` varchar(2) COLLATE utf8_bin DEFAULT NULL COMMENT '性别',
`hobby` varchar(40) COLLATE utf8_bin DEFAULT NULL COMMENT '兴趣爱好',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- ----------------------------
-- Records of intro
-- ----------------------------
INSERT INTO `intro` VALUES ('1', '小红帽', '7', '女', '我是小红帽,我喜欢我的外婆');
INSERT INTO `intro` VALUES ('2', '小明', '12', '男', '我是小明,我喜欢学习');
INSERT INTO `intro` VALUES ('3', '小亮', '13', '男', '我是小亮,我喜欢运动');
操作完后在表中可直接有几条测试数据
配置文件(YML)
#mysql
spring:
datasource:
url: jdbc:mysql://localhost:3306/testdb?characterEncoding=utf-8&serverTimezone=GMT%2B8
username: root
password: root
#端口号设置
server:
port: 8080
配置类
在这里我写了一些配置类,主要的目的也是为了后期的一个测试效果更好,主要如下
Swagger2配置类
package com.uncletj.mybatisplusdemo.config;
import com.google.common.collect.Sets;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* @Author uncletj
* @Date 2021/4/22 11:38
* @Version SpringBoot 2.2.2
* @projectName
*/
@Configuration//配置类
@EnableSwagger2//开启Swagger2的自动配置
public class SwaggerConfig {
@Bean
public Docket createRestApi(){
return new Docket(DocumentationType.SWAGGER_2)
//协议,http或https
.protocols(Sets.newHashSet("http"))
.apiInfo(apiInfo())
.select()
//controller扫描路径
.apis(RequestHandlerSelectors.basePackage("com.uncletj.mybatisplusdemo.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("mybatis-plus-demo")
.version("1.0")
.description("demo version 1.0")
.build();
}
}
返回类枚举
package com.uncletj.mybatisplusdemo.config;
/**
* @Author uncletj
* @Date 2021/4/22 14:58
* @Version SpringBoot 2.2.2
* @projectName 返回枚举
*/
public enum ResponseCode {
/** 成功 */
SUCCESS("200", "成功"),
/** 操作失败 */
ERROR("500", "操作失败");
private ResponseCode(String value, String msg){
this.val = value;
this.msg = msg;
}
public String val() {
return val;
}
public String msg() {
return msg;
}
private String val;
private String msg;
}
统一返回配置类
package com.uncletj.mybatisplusdemo.config;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @Author uncletj
* @Date 2021/4/22 14:59
* @Version SpringBoot 2.2.2
* @projectName 统一返回类
*/
@Data
@ApiModel(description = "返回响应式数据")
public class ResultData {
@ApiModelProperty(value = "编码")
private String code;
@ApiModelProperty(value = "是否成功")
private String msg;
@ApiModelProperty("返回对象")
private Object data;
private static ResultData resultData(String code, String msg, Object data) {
ResultData resultData = new ResultData();
resultData.setCode(code);
resultData.setMsg(msg);
resultData.setData(data);
return resultData;
}
//返回数据成功
public static ResultData success(Object data, String msg) {
return resultData(ResponseCode.SUCCESS.val(), msg, data);
}
//返回数据报错
public static ResultData fail(String code, String msg) {
return resultData(ResponseCode.ERROR.val(), ResponseCode.ERROR.msg(), null);
}
}
实体类
因为我们在刚刚引入了一个lombok的依赖,所以使用@Data注解可以为我们省略getter与setter方法,这样代码量也会减少很多
Intro.java
package com.uncletj.mybatisplusdemo.po;
import lombok.Data;
/**
* @Author uncletj
* @Date 2021/4/22 14:43
* @Version SpringBoot 2.2.2
* @projectName 个人介绍实体类
*/
@Data
public class Intro {
/**
* 主键id
*/
private int id;
/**
* 名称
*/
private String name;
/**
* 年龄
*/
private int age;
/**
* 性别
*/
private String gender;
/**
* 兴趣爱好
*/
private String hobby;
}
mapeer
这里直接继承BaseMapper,可以省去xml文件,也可以通过自己去创建一个xml文件编写sql
IntroMapper .java
package com.uncletj.mybatisplusdemo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.uncletj.mybatisplusdemo.po.Intro;
import org.apache.ibatis.annotations.Mapper;
/**
* @Author uncletj
* @Date 2021/4/22 11:44
* @Version SpringBoot 2.2.2
* @projectName
*/
@Mapper
public interface IntroMapper extends BaseMapper<Intro> {
}
Service
IntroService .java
package com.uncletj.mybatisplusdemo.service;
import com.uncletj.mybatisplusdemo.po.Intro;
import java.util.List;
/**
* @Author uncletj
* @Date 2021/4/22 14:52
* @Version SpringBoot 2.2.2
* @projectName
*/
public interface IntroService {
List<Intro>getBySelectIntro();
}
impl
IntroServiceImpl .java
package com.uncletj.mybatisplusdemo.service.impl;
import com.uncletj.mybatisplusdemo.mapper.IntroMapper;
import com.uncletj.mybatisplusdemo.po.Intro;
import com.uncletj.mybatisplusdemo.service.IntroService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* @Author uncletj
* @Date 2021/4/22 14:53
* @Version SpringBoot 2.2.2
* @projectName
*/
@Service
public class IntroServiceImpl implements IntroService {
@Resource
private IntroMapper introMapper;
@Override
public List<Intro> getBySelectIntro() {
return introMapper.selectList(null);
}
}
控制层
IntroController.java
package com.uncletj.mybatisplusdemo.controller;
import com.uncletj.mybatisplusdemo.config.ResponseCode;
import com.uncletj.mybatisplusdemo.config.ResultData;
import com.uncletj.mybatisplusdemo.po.Intro;
import com.uncletj.mybatisplusdemo.service.IntroService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @Author uncletj
* @Date 2021/4/22 12:00
* @Version SpringBoot 2.2.2
* @projectName
*/
@RestController
@RequestMapping(value = "intro")
public class IntroController {
@Autowired
private IntroService introService;
/**
* 查询所有数据
* @return
*/
@GetMapping("/list")
public ResultData getByIntroList(){
try {
List<Intro> list = introService.getBySelectIntro();
return ResultData.success(list,"查询数据成功");
}catch (Exception e){
e.printStackTrace();
return ResultData.fail(ResponseCode.ERROR.val(),"查询数据失败");
}
}
}
这样一个基本的操作就完成了,就是这么简单,先去测试看看结果吧!
测试之后是没问题的,大家再来看下我这边的一个控制台
日志输出
有日志输出,这个十分简单,只需要向我们的yml文件内添加以下配置即可,这样就可以实时观测我们的sql记录了
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
当然在我的另外一篇文章中有一个logback的日志输出,可以可以观测sql记录的,有兴趣也可以去看看我把链接地址放在下面
链接 | 地址 |
---|---|
设置logback.xml日志打印记录 | 点击进入 |
这个呈现的效果如下,好处是能确定在某个时间段执行了那一部分的sql
代码生成器
介绍
AutoGenerator 简介
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。与 mybatis 中的 mybatis-generator-core 类似。这个也是MyBatis-plus的一个很实用的一个功能,下面我们来看看怎么进行使用吧
删除之前的模块
可以看到我现在是把之前的模块全部删除掉了的,这个时候不要慌,我们用代码生成器一键生成,并且我还要变的比以前更全面,首先我们先去引入AutoGenerator 的依赖吧
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.1.tmp</version>
</dependency>
<!-- 添加 模板引擎 依赖 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.2</version>
</dependency>
紧接着就可以开始编写生成类了,下面写入一个AutoGeneratorTest的测试类,具体如下
package com.uncletj.mybatisplusdemo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.junit.jupiter.api.Test;
/**
* @Author uncletj
* @Date 2021/4/22 15:40
* @Version SpringBoot 2.2.2
* @projectName MyBatis-plus生成器
*/
public class AutoGenerateTest {
@Test
public void autoGenerate() {
// 1、代码生成器
AutoGenerator mpg = new AutoGenerator();
// 2、全局配置
GlobalConfig gc = new GlobalConfig();
// 填写代码生成的目录(需要修改)
String projectPath = "D://uploads//mybatis-plus-demo";
// 拼接出代码最终输出的目录
gc.setOutputDir(projectPath + "/src/main/java");
// 配置开发者信息(可选)(需要修改)
gc.setAuthor("uncletj");
// 配置是否打开目录,false 为不打开(可选)
gc.setOpen(false);
// 实体属性 Swagger2 注解,添加 Swagger 依赖,开启 Swagger2 模式(可选)
gc.setSwagger2(true);
// 重新生成文件时是否覆盖,false 表示不覆盖(可选)
gc.setFileOverride(false);
// 配置主键生成策略,此处为 ASSIGN_ID(可选)
gc.setIdType(IdType.ASSIGN_ID);
// 配置日期类型,此处为 ONLY_DATE(可选)
gc.setDateType(DateType.ONLY_DATE);
// 默认生成的 service 会有 I 前缀
gc.setServiceName("%sService");
mpg.setGlobalConfig(gc);
// 3、数据源配置(需要修改)
DataSourceConfig dsc = new DataSourceConfig();
// 配置数据库 url 地址
dsc.setUrl("jdbc:mysql://localhost:3306/testdb?characterEncoding=utf-8&serverTimezone=GMT%2B8");
// 可以直接在 url 中指定数据库名
// dsc.setSchemaName("testdb");
// 配置数据库驱动
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
// 配置数据库连接用户名
dsc.setUsername("root");
// 配置数据库连接密码
dsc.setPassword("root");
mpg.setDataSource(dsc);
// 4、包配置
PackageConfig pc = new PackageConfig();
// 配置父包名(需要修改)
pc.setParent("com.uncletj");
// 配置模块名(需要修改)
pc.setModuleName("mybatisplusdemo");
// 配置 po 包名
pc.setEntity("po");
// 配置 mapper 包名
pc.setMapper("mapper");
// 配置 service 包名
pc.setService("service");
// 配置 controller 包名
pc.setController("controller");
mpg.setPackageInfo(pc);
// 5、策略配置(数据库表配置)
StrategyConfig strategy = new StrategyConfig();
// 指定表名(可以同时操作多个表,使用 , 隔开)(需要修改)
strategy.setInclude("intro");
// 配置数据表与实体类名之间映射的策略
strategy.setNaming(NamingStrategy.underline_to_camel);
// 配置数据表的字段与实体类的属性名之间映射的策略
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
// 配置 lombok 模式
strategy.setEntityLombokModel(true);
// 配置 rest 风格的控制器(@RestController)
strategy.setRestControllerStyle(true);
// 配置驼峰转连字符
strategy.setControllerMappingHyphenStyle(true);
mpg.setStrategy(strategy);
// 6、执行代码生成操作
mpg.execute();
}
}
执行后结果如上的话你的模块也会直接显示出来了,我生成之后的模块如下,是不是有种很爽的感觉,突然之间少了一大批步骤
接口测试
下面我们什么也不做,直奔控制类而去写一个接口,看看能不能吧
package com.uncletj.mybatisplusdemo.controller;
import com.uncletj.mybatisplusdemo.config.ResponseCode;
import com.uncletj.mybatisplusdemo.config.ResultData;
import com.uncletj.mybatisplusdemo.po.Intro;
import com.uncletj.mybatisplusdemo.service.IntroService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* <p>
* 前端控制器
* </p>
*
* @author uncletj
* @since 2021-04-22
*/
@RestController
@RequestMapping("/intro")
public class IntroController {
@Autowired
private IntroService introService;
@GetMapping("/list")
public ResultData getBySelectIntroList() {
try {
List<Intro> list = introService.list();
return ResultData.success(list,"查询数据成功");
} catch (Exception e) {
e.printStackTrace();
return ResultData.fail(ResponseCode.ERROR.val(),"查询数据失败");
}
}
}
测试一下看看,结果就在眼前了
这个是真的,只是一个代码生成器,上控制类写一个接口后调用业务层直接出来数据!
IService
就是这么爽,究竟是什么让我们这么爽快的就把数据给传出来了,下面去一探究竟,一个ctrl+鼠标左键,我立马就跳转到了一个神奇的地方,就是它《IService》
IService.java
还真的是太暖心了吧,下面基本上都是一些CRUD操作,相信大家都能看得懂,用多了慢慢就熟悉了,我也就不过与太多的介绍了吧
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.baomidou.mybatisplus.extension.service;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.UpdateChainWrapper;
import com.baomidou.mybatisplus.extension.toolkit.ChainWrappers;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.springframework.transaction.annotation.Transactional;
public interface IService<T> {
int DEFAULT_BATCH_SIZE = 1000;
default boolean save(T entity) {
return SqlHelper.retBool(this.getBaseMapper().insert(entity));
}
@Transactional(
rollbackFor = {Exception.class}
)
default boolean saveBatch(Collection<T> entityList) {
return this.saveBatch(entityList, 1000);
}
boolean saveBatch(Collection<T> entityList, int batchSize);
@Transactional(
rollbackFor = {Exception.class}
)
default boolean saveOrUpdateBatch(Collection<T> entityList) {
return this.saveOrUpdateBatch(entityList, 1000);
}
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);
default boolean removeById(Serializable id) {
return SqlHelper.retBool(this.getBaseMapper().deleteById(id));
}
default boolean removeByMap(Map<String, Object> columnMap) {
Assert.notEmpty(columnMap, "error: columnMap must not be empty", new Object[0]);
return SqlHelper.retBool(this.getBaseMapper().deleteByMap(columnMap));
}
default boolean remove(Wrapper<T> queryWrapper) {
return SqlHelper.retBool(this.getBaseMapper().delete(queryWrapper));
}
default boolean removeByIds(Collection<? extends Serializable> idList) {
return CollectionUtils.isEmpty(idList) ? false : SqlHelper.retBool(this.getBaseMapper().deleteBatchIds(idList));
}
default boolean updateById(T entity) {
return SqlHelper.retBool(this.getBaseMapper().updateById(entity));
}
default boolean update(Wrapper<T> updateWrapper) {
return this.update((Object)null, updateWrapper);
}
default boolean update(T entity, Wrapper<T> updateWrapper) {
return SqlHelper.retBool(this.getBaseMapper().update(entity, updateWrapper));
}
@Transactional(
rollbackFor = {Exception.class}
)
default boolean updateBatchById(Collection<T> entityList) {
return this.updateBatchById(entityList, 1000);
}
boolean updateBatchById(Collection<T> entityList, int batchSize);
boolean saveOrUpdate(T entity);
default T getById(Serializable id) {
return this.getBaseMapper().selectById(id);
}
default List<T> listByIds(Collection<? extends Serializable> idList) {
return this.getBaseMapper().selectBatchIds(idList);
}
default List<T> listByMap(Map<String, Object> columnMap) {
return this.getBaseMapper().selectByMap(columnMap);
}
default T getOne(Wrapper<T> queryWrapper) {
return this.getOne(queryWrapper, true);
}
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
Map<String, Object> getMap(Wrapper<T> queryWrapper);
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
default int count() {
return this.count(Wrappers.emptyWrapper());
}
default int count(Wrapper<T> queryWrapper) {
return SqlHelper.retCount(this.getBaseMapper().selectCount(queryWrapper));
}
default List<T> list(Wrapper<T> queryWrapper) {
return this.getBaseMapper().selectList(queryWrapper);
}
default List<T> list() {
return this.list(Wrappers.emptyWrapper());
}
default <E extends IPage<T>> E page(E page, Wrapper<T> queryWrapper) {
return this.getBaseMapper().selectPage(page, queryWrapper);
}
default <E extends IPage<T>> E page(E page) {
return this.page(page, Wrappers.emptyWrapper());
}
default List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper) {
return this.getBaseMapper().selectMaps(queryWrapper);
}
default List<Map<String, Object>> listMaps() {
return this.listMaps(Wrappers.emptyWrapper());
}
default List<Object> listObjs() {
return this.listObjs(Function.identity());
}
default <V> List<V> listObjs(Function<? super Object, V> mapper) {
return this.listObjs(Wrappers.emptyWrapper(), mapper);
}
default List<Object> listObjs(Wrapper<T> queryWrapper) {
return this.listObjs(queryWrapper, Function.identity());
}
default <V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper) {
return (List)this.getBaseMapper().selectObjs(queryWrapper).stream().filter(Objects::nonNull).map(mapper).collect(Collectors.toList());
}
default <E extends IPage<Map<String, Object>>> E pageMaps(E page, Wrapper<T> queryWrapper) {
return this.getBaseMapper().selectMapsPage(page, queryWrapper);
}
default <E extends IPage<Map<String, Object>>> E pageMaps(E page) {
return this.pageMaps(page, Wrappers.emptyWrapper());
}
BaseMapper<T> getBaseMapper();
default QueryChainWrapper<T> query() {
return ChainWrappers.queryChain(this.getBaseMapper());
}
default LambdaQueryChainWrapper<T> lambdaQuery() {
return ChainWrappers.lambdaQueryChain(this.getBaseMapper());
}
default UpdateChainWrapper<T> update() {
return ChainWrappers.updateChain(this.getBaseMapper());
}
default LambdaUpdateChainWrapper<T> lambdaUpdate() {
return ChainWrappers.lambdaUpdateChain(this.getBaseMapper());
}
default boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper) {
return this.update(entity, updateWrapper) || this.saveOrUpdate(entity);
}
}
CRUD操作
为提升观看效果,我在此实现一遍一些简单的crud操作,其实在于MyBatis-plus提供的BaseMapper还是IService它是为我们提供了很大的方便,但是复杂的sql还是需要我们自己去完成,下面我也只做一些简单的测试,所有测试如下
package com.uncletj.mybatisplusdemo.controller;
import com.uncletj.mybatisplusdemo.config.ResponseCode;
import com.uncletj.mybatisplusdemo.config.ResultData;
import com.uncletj.mybatisplusdemo.po.Intro;
import com.uncletj.mybatisplusdemo.service.IntroService;
import io.swagger.annotations.ApiImplicitParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* <p>
* 前端控制器
* </p>
*
* @author uncletj
* @since 2021-04-22
*/
@RestController
@RequestMapping("/intro")
public class IntroController {
@Autowired
private IntroService introService;
/**
* 查询所有数据信息
* @return
*/
@GetMapping("/list")
public ResultData getBySelectIntroList() {
try {
List<Intro> list = introService.list();
return ResultData.success(list,"查询数据成功");
} catch (Exception e) {
e.printStackTrace();
return ResultData.fail(ResponseCode.ERROR.val(),"查询数据失败");
}
}
/**
* 根据Id查询数据信息
* @param id
* @return
*/
@GetMapping("byid")
@ApiImplicitParam(name = "id",value = "id",dataType = "int",paramType = "query",required = true)
public ResultData getIntroById(int id){
try {
Intro intro =introService.getById(id);
return ResultData.success(intro,"查询数据成功");
}catch (Exception e){
e.printStackTrace();
return ResultData.fail(ResponseCode.ERROR.val(),"查询数据失败");
}
}
/**
* 添加数据
* @param intro
* @return
*/
@PostMapping("/insert")
@ApiImplicitParam(name = "Intro",value = "Intro",dataType = "class",paramType = "body")
public ResultData getByIntroInsert(@RequestBody Intro intro){
try {
boolean ins =introService.save(intro);
if (ins==true){
return ResultData.success(ins,"添加数据成功");
}
return ResultData.fail(ResponseCode.ERROR.val(),"添加中出现异常,请查看");
}catch (Exception e){
e.printStackTrace();
return ResultData.fail(ResponseCode.ERROR.val(),"添加数据失败");
}
}
/**
* 根据id删除数据信息
* @param intro
* @return
*/
@DeleteMapping("/delete")
@ApiImplicitParam(name = "id",value = "id",dataType = "int",paramType = "query",required = true)
public ResultData getByIntroDel(Intro intro){
try {
boolean id =introService.removeById(intro.getId());
if (id==true){
return ResultData.success(id,"删除数据成功");
}
return ResultData.fail(ResponseCode.ERROR.val(),"删除中出现异常,请查看");
}catch (Exception e){
e.printStackTrace();
return ResultData.fail(ResponseCode.ERROR.val(),"删除数据失败");
}
}
/**
* 根据Id修改数据信息
* @param intro
* @return
*/
@PutMapping("update")
@ApiImplicitParam(name = "Intro",value = "Intro",dataType = "class",paramType = "body")
public ResultData getByIntroUpdate(@RequestBody Intro intro){
try {
boolean upl =introService.updateById(intro);
if (upl==true){
return ResultData.success(intro,"修改数据失败");
}
return ResultData.fail(ResponseCode.ERROR.val(),"修改中出现异常,请查看");
}catch (Exception e){
e.printStackTrace();
return ResultData.fail(ResponseCode.ERROR.val(),"修改数据失败");
}
}
}
以上的操作图如下
接口名称 | 作用 |
---|---|
list | 查询所有数据信息 |
byid | 根据Id查询数据信息 |
insert | 添加数据 |
delete | 根据id删除数据 |
update | 根据id修改数据 |
Swagger接口测试图如下
swagger的使用我在之前也是有做过一篇博客去介绍了一下,有兴趣的可以了解一下,Swagger是一个后端接口测试工具,使用也是十分的简单,链接如下
链接 | 地址 |
---|---|
SpringBoot集成Swagger实现api接口文档 | 点击进入 |
分页插件
编写配置类
这个类必须配置!!!
package com.duodf.uncletj.config;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* <p>
* 分页插件配置类
* </p>
*
* @author uncletj
* @since 2021-04-22
*/
@EnableTransactionManagement(proxyTargetClass = true)
@Configuration
public class MybatisPlusConfig {
/**
* mybatis-plus分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
return paginationInterceptor;
}
}
然后我又直接写控制层了,说实话自带的接口用着真香
编写控制层
/**
* 分页查找数据信息
* @return
*/
@GetMapping("/page")
public ResultData getByIntroPageList(){
try {
Page<Intro> page = new Page<>(1,2);
introService.page(page);
return ResultData.success(page,"查询数据成功");
}catch (Exception e){
e.printStackTrace();
return ResultData.fail(ResponseCode.ERROR.val(),"查询数据失败");
}
}
测试
把这个接口放到你的控制层就好了,当然我这里的初始数与分页数是定死了的,如果想变活的那也是十分简单,直接配置一个分页的工具类就好了,分页都轻松了,这就特别爽了吧,下面再来了解最后一个内容吧,乐观锁
乐观锁
何为悲欢锁
悲观锁,正如其名,具有强烈的独占和排他特性。它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度。因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制
何为乐观锁
乐观锁是相对悲观锁而言的,乐观锁假设数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则返回给用户错误的信息,让用户决定如何去做。乐观锁适用于读操作多的场景,这样可以提高程序的吞吐量
乐观锁、悲观锁使用场景
乐观锁一般用于读比较多的场合,尽量减少加锁的开销。
悲观锁一般用于写比较多的场合,尽量减少 类似 乐观锁重试更新引起的性能开销。
乐观锁两种实现方式
选项 | 操作 |
---|---|
第一种 | 通过版本号机制实现 |
第二种 | 通过 CAS 算法实现 |
本次我就使用第一种方式去实现,接下来继续表演
配置乐观锁插件
在我们的MyBatis-plus配置类下配置如下
/**
* 乐观锁插件
* @return 乐观锁插件的实例
*/
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
数据加入版本号
实体类加入对应的注解
/**
* 版本号(用于乐观锁, 默认为 1)
*/
@Version
@TableField(fill = FieldFill.INSERT)
private Integer version;
自定义类Handler
package com.uncletj.mybatisplusdemo.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* @Author uncletj
* @Date 2021/4/22
* @projectName 自定义
*/
@Component
public class MyBatisHanlder implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "version", Integer.class, 1);
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
}
}
测试
接下来就可以测试了!我这边写了一个测试类
package com.uncletj.mybatisplusdemo;
import com.uncletj.mybatisplusdemo.po.Intro;
import com.uncletj.mybatisplusdemo.service.IntroService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
@SpringBootTest
class MybatisPlusDemoApplicationTests {
@Resource
private IntroService introService;
@Test
void contextLoads() {
Intro intro = new Intro();
intro.setName("藤井").setAge(12).setGender("无").setHobby("不知道些什么兴趣");
introService.save(intro);
introService.list().forEach(System.out::println);
intro.setName("藤井大叔不骄傲");
introService.update(intro,null);
introService.list().forEach(System.out::println);
}
}
查看结果
根据结果得出,首先添加之前版本号是为1,修改之后查询出来的版本号为2
————————————————————————————————————————
这版就到此结束了 ,基本上MyBatis-plus比较实用的功能都应该是列出来了,如有缺漏的,还请指教
不要认为自己很强,也不要以为自己很弱,迷茫不是归宿