MyBatis-Plus学习笔记
官方介绍
mybatis-plus可以理解为加强版的mybatis,可以帮我们减少编写mapper中简单的sql语句,你可以理解为IPhone13 和 IPhone13 Plus
官网是这么说的:MyBatis-Plus (简称 MP)是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
并且还列出了以下特性:
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作
你了解它是一个便捷的Mybatis工具后,我们开始操作
上手练练
准备工作
首先,现在新建数据库mybatisplus
并建两张表分别为category(种类表)和product(商品表):
DROP TABLE IF EXISTS `category`;
CREATE TABLE `category` (
`cid` int(11) NOT NULL AUTO_INCREMENT,
`category_name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`cid`)
);
DROP TABLE IF EXISTS `product`;
CREATE TABLE `product` (
`pid` int(11) NOT NULL AUTO_INCREMENT,
`product_name` varchar(50) NOT NULL,
`category_id` int(11) NOT NULL,
`price` decimal(10,2) DEFAULT NULL,
PRIMARY KEY (`pid`)
);
如下图,随便添加一两条数据,这里就不写sql语句了,手动添加:
新建一个maven项目,导入相关依赖包:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--日志 依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--mybatis-plus 依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<!--mysql 连接依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.37</version>
</dependency>
</dependencies>
在application.properties
进行相关的配置 (图中带汉字的需要根据你的配置去修改):
### 数据源配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatisplus?serverTimezone=UTC
spring.datasource.username=你的mysql用户名
spring.datasource.password=你的mysql密码
##mybatis配置
###扫描mapper文件路径
mybatis-plus.mapper-locations=classpath:mapper/*.xml
mybatis-plus.type-aliases-package=com.melo.entity(修改成你的实体类包名)
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#开启驼峰命名
mybatis-plus.configuration.map-underscore-to-camel-case=true
项目目录结构如此:
虽然我们可以少写mapper中的代码,可是一些复杂逻辑的代码还需要我们自己去编写,所以他其实并不改变正常的mybatis书写
实体类Product
代码:
package com.melo.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Author Melo
* @Desc 商品实体类
* @Date 2023/10/26 15:11
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName(value = "product") //对应数据库中的表名
public class Product {
@TableId(type = IdType.AUTO) //标注主键ID(自增)
private Long pid;
private String productName;
private Long categoryId;
private Double price;
}
接口文件ProductMapper
代码:
package com.melo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.melo.entity.Product;
import org.apache.ibatis.annotations.Mapper;
/**
* @Author Melo
* @Desc 商品Mapper接口文件
* @Date 2023/10/26 20:30
*/
@Mapper
public interface ProductMapper extends BaseMapper<Product> {
}
因为使用了mybatis-plus工具,所以ProductMapper
需要继承BaseMapper<Product>
。
其中<>放你需要操作的实体类对象名称
基本操作 CRUD
有了以上的就足够了,我们在测试MybatisplusApplicationTests
里面具体练习使用mybatisplus的操作:
使用方法如下:
package com.melo;
import com.melo.entity.Product;
import com.melo.mapper.ProductMapper;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.util.List;
@SpringBootTest
@Slf4j
class MybatisplusApplicationTests {
@Resource
private ProductMapper productMapper;
@Test
void contextLoads() {
}
@Test
@DisplayName("测试插入数据")
public void testInsert(){
Product product = new Product();
product.setProductName("Macbook笔记本电脑");
product.setCategoryId(1l);
product.setPrice(19999.00);
int result = productMapper.insert(product);
log.info("testInsert:{}",result);
log.info("product:{}",product);
}
@Test
@DisplayName("测试查询数据")
public void testSelectById() {
Product product = productMapper.selectById(3L);
log.info("product:{}", product);
}
@Test
@DisplayName("测试查询全部数据")
public void testSelectList(){
List<Product> products = productMapper.selectList(null);
log.info("testSelectList:{}",products);
}
@Test
@DisplayName("测试更新数据")
public void testUpdateById(){
Product product = new Product();
product.setPid(3L);
product.setProductName("小米手机");
product.setPrice(3499.00);
int result = productMapper.updateById(product);
log.info("测试更新:{}",result);
log.info("product:{}",product);
}
@Test
@DisplayName("测试删除数据")
public void testDeleteByid(){
int result = productMapper.deleteById(4L);
log.info("testSelectList:{}",result);
}
}
复杂操作
我们知道在依赖文件中并没有导入mybatis的依赖,只是导入了mybatis-plus工具的依赖,其实只用导入后者也可以进行sql语句的编写,只是大部分情况下用到的都是简单的增删改查操作,所以就使用工具内置的方法。
注:尽量只导入其中一个依赖,否则会产生依赖冲突问题
通过三种复杂情况说明简单举例:
流程和正常写mapper层代码一样,首先定义ProductMapper
接口文件:
package com.melo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.melo.entity.Product;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
* @Author Melo
* @Desc 商品dao层接口
* @Date 2023/10/26 15:22
*/
@Mapper
public interface ProductMapper extends BaseMapper<Product> {
/**
* 批量插入
*
* @param list 列表
*/
void batchInsert(@Param("list") List<Product> list);
/**
* 选择产品类别
*
* @return 是List集合但是转为Map
*/
@MapKey("pid") //将 List 结果集转换为 <key,value> 形式放入 map 结果集,方便快速查找
List<Map> selectProductWithCategory();
@MapKey("pid")
List<Map> selectProductWithCategoryByMap(Map<String,Object> map);
}
ProductMapper
xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.melo.mapper.ProductMapper">
<insert id="batchInsert">
insert into product (product_name,category_id,price)
values
<foreach collection="ProductList" item="product" separator=",">
(#{product.productName},#{product.categoryId},#{product.price})
</foreach>
</insert>
<select id="selectProductWithCategory" resultType="java.util.Map">
select p.pid, p.product_name, c.category_name, p.price
from product p
left join category c
on p.category_id = c.cid
</select>
<select id="selectProductWithCategoryByMap" resultType="java.util.Map">
select p.pid, p.product_name, c.category_name, p.price
from product p
left join category c on p.category_id = c.cid
<where>
<if test="categoryId != null and categoryId != ''">
and p.category_id=#{categoryId}
</if>
<if test="pid != null and pid != ''">
and p.pid=#{pid}
</if>
</where>
</select>
</mapper>
测试文件只需添加三个测试方法:
@Test
@DisplayName("测试批量插入商品数据")
public void testBatchInsert(){
List<Product> list = new ArrayList<>();
list.add(new Product(null,"华为mate40",1l,7000.00));
list.add(new Product(null,"华为mate40",1l,7000.00));
list.add(new Product(null,"华为mate40",1l,7000.00));
productMapper.batchInsert(list);
log.info("list:{}",list);
}
@Test
@DisplayName("测试查询带分类的商品数据")
public void testSelectProductWithCategory(){
List<Map> maps = productMapper.selectProductWithCategory();
maps.stream().forEach(item->{
log.info("testSelectProductWithCategory:{}",item);
});
}
@Test
@DisplayName("测试条件查询带分类的商品数据")
public void testSelectProductWithCategoryByMap(){
Map<String,Object> params = new HashMap<>();
params.put("categoryId",1l);
params.put("pid",4l);
List<Map> maps = productMapper.selectProductWithCategoryByMap(params);
maps.stream().forEach(item->{
log.info("testSelectProductWithCategoryByMap:{}",item);
});
}
别的玩法
分页查询
分页查询在我们的需求中也是十分常见的,之前我们使用的工具为pageHelper
现在mybatis-plus自己实现了分页查询
首先需要进行分页查询的配置:
package com.melo.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author Melo
* @Desc mybatis-plus配置类
* @Date 2023/10/26 16:48
*/
@Configuration
public class MybatisPlusConfig {
/**
* 添加分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//如果配置多个插件,切记分页最后添加
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
//interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 如果有多数据源可以不配具体类型 否则都建议配上具体的DbType
return interceptor;
}
}
测试:
@Test
@DisplayName("分页查询")
public void testSelectPage(){
QueryWrapper<Product> wrapper = new QueryWrapper<>();
IPage<Product> page = new Page<>(0,2);
page = productMapper.selectPage(page,wrapper);
List<Product> productList = page.getRecords();
log.info("testSelectPage:{}",productList);
}
条件构造器
封装了一些条件查询的包装器,简单使用如下:
@Test
@DisplayName("根据商品名查询商品")
public void testQueryWrapper(){
//创建查询条件对象
QueryWrapper<Product> wrapper = new QueryWrapper<>();
//设置返回字段
wrapper.select("product_name","price");
//添加查询条件
wrapper.eq("product_name","小米手机")
.ge("price",2000.00);
//查询
List<Product> products = productMapper.selectList(wrapper);
log.info("testQueryWrapper:{}",products);
}
以上就是本文全部内容,想学习更多的可以去官网继续学习
文章知识点来源:https://baomidou.com/