MyBatis-Plus与Springboot整合
MyBatis-Plus官网:http://www.baomidou.com
1. MyBatis-Plus介绍
1.1 MyBatis-Plus简介
简称MP,是MyBatis的增强工具(并不是取代),在MyBatis原有技术之上进行的增强,而不是改变,简化了MyBatis开发步骤,常见的操作封装成了方法。提升了开发效率。
1.2 特性
无侵入:不做改变,引入不会对原有工程产生任何影响。
损耗小:常见的CRUD操作自动注入,直接面向对象。
强大数据操作(CRUD):将常规Mapper操作,进一步进行了封装,直接可以通过调用方法的形式来实现数据库的CRUD。
自动生成主键:支持主键的生成策略。
内嵌代码生成器:采用内置插件,可以快速生成Mapper的映射。
内置分页插件:基于MyBatis物理实现分页。
…
1.3 支持数据库
支持的关系型种类:
- MySQL、MariaDB、DB2、Oracle、SQL Server、SQLite…
- 达梦、虚谷、南大…
1.4 MyBatis-Plus架构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UkpaEYWK-1668165984706)(/Users/yuanxin/Documents/课件/SpringBoot-V2.1-20220710/unit03-Spring Boot数据访问/01-Spring Boot数据访问教程/images/8.jpeg)]
2.SpringBoot整合MyBatis-Plus
1 MyBatis-Plus配置
1.引入依赖:MyBatis-Plus依赖。
l<!-- 项目依赖 -->
<dependencies>
<!-- 引入了单元测试的启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 1.MySQL数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- 连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.17</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
</dependencies>
2.创建对应的表语句。
CREATE TABLE t_product (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50), #商品名称
price DOUBLE,
flag VARCHAR(2), #上架状态
goods_desc VARCHAR(100), #商品描述
images VARCHAR(400), #商品图片
goods_stock INT, #商品库存
goods_type VARCHAR(20), #商品类型
created_user VARCHAR(20) COMMENT '日志-创建人',
created_time DATETIME COMMENT '日志-创建时间',
modified_user VARCHAR(20) COMMENT '日志-最后修改执行人',
modified_time DATETIME COMMENT '日志-最后修改时间'
);
INSERT INTO t_product VALUES (
NULL,
'HUAWEI P60',
6999,
'1',
'华为P60 5G手机 分期 麒麟990 晨曦金 8+256GB',
'https://img14.360buyimg.com/5f4da578E7c6efde1/2cd53a53083ab2ed.jpg',
99,
'1',
'admin',
'2022-11-04 15:46:55',
'Tom',
'2022-11-04 15:46:55');
2.配置properties文件中配置数据库连接相关的信息。
spring.datasource.url=jdbc:mysql://localhost:3306/springbootdata?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.initialSize=20
spring.datasource.minIdle=10
spring.datasource.maxActive=100
# 开启驼峰命名匹配映射 mybatis-plus内置驼峰映射
#mybatis-plus.configuration.map-underscore-to-camel-case=true
# 输出SQL语句
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# 配置MyBatis的XML配置文件位置
mybatis-plus.mapper-locations=classpath:mapper/*.xml
# 配置XML映射文件中指定的实体类别名路径
mybatis-plus.type-aliases-package=com.cy.domain
3.编译一个实体类pojo,映射一张表-Product。
- @TableName(“表明”):表示当前实体类映射数据库中的那一张表
- @TableFiled(“表的字段名称”):在表中的字段名称实体类中的属性名称不一致的时候,需要开启映射。
package com.lty.pojo;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.omg.CORBA.IDLType;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.io.Serializable;
/**
* (TProduct)实体类
*
* @author makejava
* @since 2022-11-11 09:54:29
*/
//mybatisplus提供了一个映射的注解@TableName("表明“)
@Component
// @TableName("t_product")
public class Product implements Serializable {
private static final long serialVersionUID = 348863888757284637L;
//指定当前实体类中中的属性哪一个与表中的id映射
//@TableId(type= IdType.AUTO) //支持id自增策略
private Integer id;
private String name;
private String price;
private String flag;
// @TableField("goods_desc") //映射关系
private String goodsDesc;
private String images;
private Integer goodsStock;
private String goodsType;
/**
* 日志-创建人
*/
private String createdUser;
/**
* 日志-创建时间
*/
//@JsonFormat(pattern = "yyyy-MM-dd",timezone = "UTC")
//插入时填充值 FiledFill.INSERT
@TableField(fill = FieldFill.INSERT)
private Date createdTime;
/**
* 日志-最后修改执行人
*/
private String modifiedUser;
/**
* 日志-最后修改时间
*/
// @JsonFormat(pattern = "yyyy-MM-dd",timezone = "UTC")
@TableField(fill = FieldFill.INSERT_UPDATE) //插入与更新时自动填充
private Date modifiedTime;
get/set....
4.配置Druid连接池,并且通过配置类加载指定的连接池(DruidDataSource)。
package com.cy.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource getDruid() {
return new DruidDataSource();
}
}
2 Mapper层开发
1.创建Mapper层接口,需要实现一个MyBatis-Plus提供的BaseMapper接口。
BaseMapper: 在该接口中封装数据库的常见操作,增删改查。通过方法的调用直接可以完成简单的数据库操作。
package com.cy.mybaitspluspro.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.cy.mybaitspluspro.pojo.Product;
import org.apache.ibatis.annotations.Mapper;
@Mapper // 将当前的接口对应的实现类交给MyBatis工厂来创建
public interface ProductMapper extends BaseMapper<Product> {
// 不需要编写任何的CRUD操作的方法,天然具有了增删改查的操作
}
2.配置MyBatis-Plus复杂SQL操作的信息。
# 开启驼峰命名匹配映射
#mybatis-plus.configuration.map-underscore-to-camel-case=true
# 输出SQL语句
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# 配置MyBatis的XML配置文件位置
mybatis-plus.mapper-locations=classpath:mapper/*.xml
# 配置XML映射文件中指定的实体类别名路径(com.cy.mybatis-plus-demo.pojo.Product)
mybatis-plus.type-aliases-package=com.cy.mybaitspluspro.pojo
3 MyBatis-Plus增删改查
测试包下,创建类MyBatisPlusTests。
1.新增数据数据。insert(T entity)。
2.删除操作:
- 根据id删除
- 根据集合中的数据删除
- 根据指定的条件删除
// 根据id删除数据
@Test
public void test02() {
int row = productMapper.deleteById(1);
System.out.println("row=" + row);
}
// 根据ids删除数据
@Test
public void test03() {
ArrayList<Integer> ids = new ArrayList<>(){{
add(2);
add(3);
}};
// ids.add(1);
int row = productMapper.deleteBatchIds(ids);
System.out.println("row=" + 2);
}
// 根据条件删除数据
@Test
public void test04() {
// 使用Map接收条件(where的条件)
// price: 1999
// name: 小米
Map<String, Object> col = new HashMap<>(){{
put("name", "小米");
put("price", 1999);
}};
int row = productMapper.deleteByMap(col);
System.out.println("row=" + row);
}
@Test
public void test05() {
/**
* Wrapper<T> queryWrapper:表示封装的是一个删除条件的对象,读取queryWrapper中的条件,根据设置的条件来删除内容
*
* int delete(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
* 根据entity条件,删除记录
* 方法:@param queryWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
*/
// 条件构造器:用来封装删除条件的对象
UpdateWrapper<Product> wrapper = new UpdateWrapper<>();
// gt(): 大于,where price > 1000 OR id = 10, name like "%小米%"
wrapper.gt("price", 2000).or().likeRight("name", "小米");
productMapper.delete(wrapper);
}
3.修改数据操作。
// 根据商品id更新数据
@Test
public void test06() {
Product product = new Product();
product.setId(1); // 根据此id来修改数据库中对应的这条记录
// 将需要被更新的数据绑定在Product属性上
product.setName("小米");
product.setPrice(2999);
int row = productMapper.updateById(product);
System.out.println("row=" + row);
}
@Test
public void test07() {
Product product = new Product();
product.setId(1); // 更新的是商品id为1的这件商品
// 需要指定泛型的类型:即表示映射的表对应的实体类
UpdateWrapper<Product> wrapper = new UpdateWrapper<>();
// 条件构造器:添加跟新约束的条件
// update t_product set name="小米旗舰机", price=3999 where goods_stock>10
// ge(): 表示大于等于
// name - 小米旗舰机
// price - 3999
wrapper.ge("goods_stock", 10).set("name", "小米旗舰机").set("price", 3999).set(false, "goods_stock", null);
int row = productMapper.update(product, wrapper);
System.out.println("row=" + row);
}
4.查询数据。
@Test
public void test08() {
Product product = productMapper.selectById(1);
System.err.println(product);
}
@Test
public void test09() {
List<Integer> ids = new ArrayList<>(){{
add(1);
add(2);
}};
List<Product> products = productMapper.selectBatchIds(ids); // 批量查询数据
// 输出集合中的所有元素的信息 jdk8的新特性
products.forEach(System.out::println);
}
@Test
public void test10() {
// 需求:查询商品的名称是"小米"并且库存大于等于5
UpdateWrapper<Product> wrapper = new UpdateWrapper<>();
wrapper.ge("goods_stock", 5).eq("name", "小米");
// 快捷键:soutc
productMapper.selectList(wrapper).forEach(System.out::println);
}
5.条件+分页查询。
- selectPage():表示根据条件进行分页查询。
- Page: 封装查询页的信息
- UpdateWrapper:查询的条件构造器
@Test
public void test13(){
//根据条件进行分页查询
//分页信息 需要传递表的实体类映射
IPage<Product> page=new Page<>(1,1);
//件构造器----使用queryWrapper 增删改使用updateWrapper
QueryWrapper<Product> wrapper = new QueryWrapper<>();
wrapper.like("name","米");
IPage<Product> productIPage = productMapper.selectPage(page, wrapper);
List<Product> list = productIPage.getRecords();
for (Product product1 : list) {
System.out.println(product1);
}
}
运行后我们会发现,并没有实现分页功能,仍旧输出了满足条件查询下的所有,因此,需要写如下配置:
@Configuration
public class PageConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
6.MyBatis-Plus复杂查询
1.TableFiled字段:设置某些字段的默认取值(在某种情况下被触发)。
- FieldFill.ISERT:只有在插入时才会自动填充字段的取值
- FieldFill.INSERT_UPDATE: 只有在插入或者跟新的时候字段自动取值
//插入时填充值 FiledFill.INSERT
@TableField(fill = FieldFill.INSERT)
private Date createdTime;
/**
* 日志-最后修改执行人
*/
private String modifiedUser;
/**
* 日志-最后修改时间
*/
// @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
@TableField(fill = FieldFill.INSERT_UPDATE) //插入与更新时自动填充
private Date modifiedTime;
2.定义处理器(Handler),配置对象源数据信息(就是默认值的意思)。
- MetaObjectHandler接口:表示给指定的pojo实体类设置默认的取值(在什么状态下)。
- 实现接口中的方法即可。
//自定义源数据对象处理器,设置pojo实体类字段的默认值
@Component //非mvc层
public class MetaObject implements MetaObjectHandler {
//插入时调用
@Override
public void insertFill(org.apache.ibatis.reflection.MetaObject metaObject) {
//自动填充创建事件和修改时间
/**
* mybatisPlus3.3.3 版本后可用
* 参数1:操作的对象
* 参数2:哪个属性设置默认取值
* 参数3:目标取值的数据类型.class
* 参数4:目标属性的默认具体取值
*/
this.strictInsertFill(metaObject, "createdTime", Date.class, new Date());
this.strictInsertFill(metaObject, "modifiedTime", Date.class, new Date());
}
//跟新时调用
@Override
public void updateFill(org.apache.ibatis.reflection.MetaObject metaObject) {
//修改时调用
this.strictUpdateFill(metaObject, "modifiedTime", Date.class, new Date());
}
}
**注意:**数据库插入的时间可能不是当前系统时间
解决办法:可能url的时区有问题,可以改为:
url: jdbc:mysql://localhost/mybatis-plus?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
3.简化版连接数据库
上面我们导入了druid数据库连接池的jar包,然后配置了type: com.alibaba.druid.pool.DruidDataSource
,然后我们配置了数据库的配置类。
简化版:
- 只导入
druid-spring-boot-starter
的jar包与·mysql
的jar包 - 无需配置数据库连接池的类型
- 无需写数据库的配置类
- 可以直接使用
**原因:**druid的启动器里面已经包含了druid的jar包,sprigboot会自动识别配置
4. 使用MybatisPlus的高级配置
# 开启驼峰命名匹配映射
#mybatis-plus.configuration.map-underscore-to-camel-case=true
# 输出SQL语句
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# 配置MyBatis的XML配置文件位置
mybatis-plus.mapper-locations=classpath:mapper/*.xml
# 配置XML映射文件中指定的实体类别名路径
mybatis-plus.type-aliases-package=com.lty.domain
# 配置全局表的前缀 可以省略@TableName
mybatis-plus.global-config.db-config.table-prefix=t_
#配置全局id自增 可以省略@TableId(Type = IdType.AUTO)
mybatis-plus.global-config.db-config.id-type=auto
5. 条件构造器(基本操作):
1. 比较
- eq:等于
- ne:不等于
- gt:大于
- ge:大于等于
- lt:小于
- le:小于等于
- between
- notBetween
- in:字段 IN (value.get(0), value.get(1), …)
- notIn:字段 NOT IN (v0, v1, …)
2. 模糊查询
- like:LIKE ‘%值%’
- likeLeft : LIKE ‘%值’
- likeRight:LIKE ‘值%’
3. 排序
- orderBy 默认升序
- OrderByAsc:ORDER BY 字段, … ASC 升序
- prderByDesc:排序:ORDER BY 字段, … DESC
4. 逻辑查询
- or:主动调用 or 表示紧接着下一个方法不是用 and 连接!(不调用 or 则默认为使用 and 连接)
- and:例: and(i -> i.eq(“name”, “李白”).ne(“status”, “活着”)) —> and (name = ‘李白’ and status
<> ‘活着’)
6. ActiveRecord
什么是ActiveRecord?
ActiveRecord也属于ORM(对象关系映射)层,由Rails最早提出,遵循标准的ORM模型:表映射到记录,记
录映射到对象,字段映射到对象属性。配合遵循的命名和配置惯例,能够很大程度的快速实现模型的操作,而
且简洁易懂。
ActiveRecord的主要思想是:
每一个数据库表对应创建一个类,类的每一个对象实例对应于数据库中表的一行记录;
通常表的每个字段在类中都有相应的Field;
ActiveRecord同时负责把自己持久化,在ActiveRecord中封装了对数据库的访问,即CURD;;
ActiveRecord是一种领域模型(Domain Model),封装了部分业务逻辑;
1. 开启AR
在MP中,开启AR非常简单,只需要将实体对象继承Model即可。
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User extends Model<User> {
private Long id;
private String userName;
private String password;
private String name;
private Integer age;
private String email;
}
2.根据主键查询
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void testAR() {
User user = new User();
user.setId(2L);
User user2 = user.selectById();
System.out.println(user2);
}
}
3. 新增数据
RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void testAR() {
User user = new User();
user.setName("刘备");
user.setAge(30);
user.setPassword("123456");
user.setUserName("liubei");
user.setEmail("liubei@itcast.cn");
boolean insert = user.insert();
System.out.println(insert);
4.更新操作
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void testAR() {
User user = new User();
user.setId(8L);
user.setAge(35);
boolean update = user.updateById();
System.out.println(update);
}
}
5. 删除
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void testAR() {
User user = new User();
user.setId(7L);
boolean delete = user.deleteById();
System.out.println(delete);
}
}
结果:
[main] [cn.itcast.mp.mapper.UserMapper.deleteById]-[DEBUG] ==> Preparing: DELETE FROM
tb_user WHERE id=?
[main] [cn.itcast.mp.mapper.UserMapper.deleteById]-[DEBUG] ==> Parameters: 7(Long)
[main] [cn.itcast.mp.mapper.UserMapper.deleteById]-[DEBUG] <== Updates: 1
6. 根据条件查询
RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void testAR() {
User user = new User();
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
userQueryWrapper.le("age","20");
List<User> users = user.selectList(userQueryWrapper);
for (User user1 : users) {
System.out.println(user1);
}
}
}