一、Mybatis-Plus 是什么
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
- 润物无声
只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑。 - 效率至上
只需简单配置,即可快速进行 CRUD 操作,从而节省大量时间。 - 丰富功能
热加载、代码生成、分页、性能分析等功能一应俱全。
二、Mybatis-Plus 入门案例
1、创建数据库,创建数据库表
CREATE DATABASE `mybatis_plus`;
USE `mybatis_plus`;
CREATE TABLE `user`(
id BIGINT(20)NOT NULL COMMENT '主键ID',
NAME VARCHAR(30)NULL DEFAULT NULL COMMENT '姓名',
age INT(11)NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50)NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
)
INSERT INTO `user` (id, NAME, age, email)VALUES
(1, 'Justin', 18, 'test1@baomidou.com'),
(2, 'Jay', 20, 'test2@baomidou.com'),
(3, 'Allen', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Lay', 24, 'test5@baomidou.com');
SELECT * FROM USER;
2、创建 springboot 项目,引入相关依赖(mybatis-plus依赖、mysql驱动、lombok依赖)
<!-- mybatis-plus依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
3、编写配置文件application.properties
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root
4、创建实体类User,字段与数据库表字段保持一致,并编写mapper接口
@Repository
public interface UserMapper extends BaseMapper<User> {
}
只需要继承 BaseMapper 即可,里面有已经封装好的方法
由于运行过程中要动态生成实现类对象,要在主启动类中注明包扫描路径:
5、测试
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void findAll() {
List<User> users = userMapper.selectList(null);
System.out.println(users);
}
}
6、查看日志
在 application.properties 配置文件中加入
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
再次运行测试类,可以看到底层生成的语句:
三、Mybatis-Plus 实现增加功能
@Test
public void insert() {
User user = new User();
user.setName("William");
user.setAge(23);
user.setEmail("3245@qq.com");
int res = userMapper.insert(user);
System.out.println(res); // 返回值是影响行数
}
创建数据库表时没有让主键自增,且在上面 insert 一条记录时,也没有设置主键,但可以看到数据库中的这条记录有主键,这是因为 mybatis-plus 拥有默认的主键策略:
全局设置主键生成策略:
mybatis-plus.global-config.db-config.id-type=auto
四、Mybatis-Plus 修改
3.1、自动填充
mybatis-plus 实现修改功能:
@Test
public void update() {
User user = new User();
user.setId(1432976455618318338L);
user.setName("Leo");
int res = userMapper.updateById(user);
System.out.println(res);
}
可以看到,在进行修改或者插入时,要修改或插入的属性值都要 set 设置值。而当项目中遇到一些数据,每次都使用相同的方式填充,例如记录的创建时间,更新时间等。我们可使用MyBatis Plus的自动填充功能,完成这些字段的赋值工作。
1、在数据库表中添加 create_time,update_time 字段,在实体类中添加相应属性并在要自动填充属性上加上注解
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.UPDATE)
private Date updateTime;
2、创建类实现接口,实现接口两个方法,一个方法添加时候执行,另一个修改时候执行,在这两个方法中设置添加什么值
@Component
public class MyMateObjectHandler implements MetaObjectHandler {
// 执行添加操作,使用这个方法
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime", new Date(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
}
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime", new Date(), metaObject);
}
}
3、再次运行上面写的 insert、update 方法,不设置 create_time、update_time 两个字段的值,但数据库中有值,即mybatis-plus 的自动填充功能
3.2、乐观锁
当要更新一条记录的时候,希望这条记录没有被别人更新,也就是说实现线程安全的数据更新(解决丢失更新问题)
乐观锁实现方式:
取出记录时,获取当前version
更新时,带上这个version
执行更新时, set version = newVersion where version = oldVersion
如果version不对,就更新失败
在 mybatis-plus 中实现乐观锁:
1、在数据库中加入 version 版本字段,然后在实体类中添加该属性
@Version
@TableField(fill = FieldFill.INSERT) // 每次新插入一条数据时,都把version设置为1
private Integer version;
2、配置乐观锁插件
@Configuration
@MapperScan("com.atguigu.mptest.mapper")
public class MpConfig {
// 配置乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
3、测试
// 测试乐观锁
@Test
public void testOptimisticLocker() {
// 根据id查询
User user = userMapper.selectById(1433002670349680641L);
// 修改
user.setName("小米");
userMapper.updateById(user);
}
新插入一条数据时,可以看到版本号为1,然后修改该条新插入的数据的 name 属性值时,可以在数据库中看到 version变为2。
五、Mybatis-Plus 删除
1、根据 id 删除
// 根据id删除
@Test
public void deleteById() {
int res = userMapper.deleteById(5); // 影响行数
System.out.println(res);
}
2、批量删除
// 批量删除
@Test
public void deleteBatch() {
int res = userMapper.deleteBatchIds(Arrays.asList(2, 3));
System.out.println(res);
}
3、简单条件删除
// 简单条件删除
@Test
public void deleteConditional() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("name", "Leo");
map.put("age", 0);
int res = userMapper.deleteByMap(map);
System.out.println(res);
}
4、逻辑删除
物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除数据。
逻辑删除:假删除,将对应数据中代表是否被删除字段状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录。
逻辑删除的使用场景:可以进行数据恢复;有关联数据,不便删除。
实现:
首先在数据库中增加 deleted 字段,在实体类中也增加相应字段
@TableLogic
@TableField(fill = FieldFill.INSERT)
private Integer deleted;
然后测试
// 逻辑删除
@Test
public void deleteLogical() {
int res = userMapper.deleteById(1433039561954484226L);
System.out.println(res);
}
再查看数据库,可以看到只是 deleted 字段的值由 0 变成了 1,但使用 findAll 查询时候查不到。
六、Mybatis-Plus 查询
1、多个id的批量查询
@Test
public void testBatchSelect() {
List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
System.out.println(users);
}
2、简单条件查询
@Test
public void testConditionSelect() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("name", "Jay");
map.put("age", 20);
List<User> users = userMapper.selectByMap(map);
System.out.println(users);
}
3、分页查询
首先配置分页插件
// 配置分页插件
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
编写分页代码
@Test
public void testPageSelect() {
// 创建Page对象,传入2个参数,一个是当前页,一个是每页记录数
Page<User> page = new Page<User>(1, 2);
// 调用mybatis plus的方法实现分页
Page<User> userPage = userMapper.selectPage(page, null);
long pages = userPage.getPages(); // 总页数
long current = userPage.getCurrent(); // 当前页
List<User> records = userPage.getRecords(); // 查询数据集合
long total = userPage.getTotal(); // 总记录数
boolean hasNext = userPage.hasNext(); // 是否有下一页
boolean hasPrevious = userPage.hasPrevious(); // 是否有上一页
System.out.println("共" + pages + "页,当前在第" + current + "页,总共" + total + "条数据");
}
七、条件构造器和常用接口
通常使用 QueryQrapper 进行复杂条件查询
@Test
public void testWrapperSelect() {
QueryWrapper<User> wrapper = new QueryWrapper<User>();
// ge、gt、le、lt、isNull、isNotNull
//wrapper.ge("age", 21); // 查找年龄大于等于21的
//eq、ne
// between、notBetween
//like、notLike、likeLeft、likeRight 模糊查询
wrapper.like("name", "y"); // 名字里面包含y的
List<User> users = userMapper.selectList(wrapper);
System.out.println(users);
}