MyBatis-Plus

https://mp.baomidou.com/==>快速开始

1. Mybatis-Plus依赖

1
2
3
4
5
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1.tmp</version>
</dependency>

2. 数据库设计

1
2
3
4
5
6
7
8
9
10
11
drop table if exists user;

create table user(
id bigint(20) not null comment '主键ID',
name varchar(30) not null comment '姓名',
age int(11) not null comment '年龄',
email varchar(50) not null comment '邮件',
create_time timestamp comment '注册时间',
update_time timestamp comment '更新时间',
primary key (id)
)

3. lombok

3.1. Maven依赖

1
2
3
4
5
6
<!-- 简化实体类 get/set方法-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

intelliJ IDEA设置

3.2. @Data

添加在实体类上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.runaccpeted.mybatisplus.entity;

import lombok.Data;
import java.util.Date;

@Data
public class User {

private Long id;
private String name;
private Integer age;
private Date createTime;
private Date updateTime;
}

3.3. get/set自动生成

4. application.properties

1
2
3
4
5
6
7
8
9
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/login?useSSL=false
spring.datasource.username=root
spring.datasource.password=mysql123//

#驼峰命令
#mybatis-plus.configuration.map-underscore-to-camel-case=true
#sql语句输出到控制台
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

5. extends BaseMapper< Object>

1
2
3
4
5
6
7
8
9
package com.runaccpeted.mybatisplus.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.runaccpeted.mybatisplus.entity.User;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

public interface UserMapper extends BaseMapper<User> {
}

5.1. BaseMapper 已定义方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public interface BaseMapper<T> extends Mapper<T> {
int insert(T entity);

int deleteById(Serializable id);

int deleteByMap(@Param("cm") Map<String, Object> columnMap);

int delete(@Param("ew") Wrapper<T> wrapper);

int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);

int updateById(@Param("et") T entity);

int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);

T selectById(Serializable id);

List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);

List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);

T selectOne(@Param("ew") Wrapper<T> queryWrapper);

Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);

List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);

List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);

List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);

<E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);

<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param("ew") Wrapper<T> queryWrapper);
}

6. 添加@MapperScan

1
2
3
4
5
6
7
8
9
@SpringBootApplication
@MapperScan(basePackages = "com.runaccpeted.mybatisplus.mapper")
public class MybatisplusApplication {

public static void main(String[] args) {
SpringApplication.run(MybatisplusApplication.class, args);
}

}

7. CRUD测试

1
2
3
4
5
6
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>

Test.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.runaccpeted.mybatisplus;

import com.runaccpeted.mybatisplus.entity.User;
import com.runaccpeted.mybatisplus.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Date;

@RunWith(SpringRunner.class)
@SpringBootTest
class MybatisplusApplicationTests {

@Autowired
UserMapper userMapper;

@Test
void contextLoads() {

User user = new User();
user.setName("tom");
user.setAge(80);
user.setEmail("wt@163.com");
userMapper.insert(user);
}

}

7.1. 分布式id生成策略

分布式id生成方案总结

分布式系统唯一ID生成方案汇总

mybatis-plus自生成的id是一串数字 1233005715855114242

即默认采用的是snowflake算法

1
2
@TableId(type = IdType.ASSIGN_ID) 
private Long id;

7.1.1. IdType

描述
AUTO 数据库ID自增
NONE 无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
INPUT insert前自行set主键值
ASSIGN_ID 分配ID(主键类型为Number(Long和Integer)或String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)
ASSIGN_UUID 分配UUID,主键类型为String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认default方法)
ID_WORKER 分布式全局唯一ID 长整型类型(please use ASSIGN_ID)
UUID 32位UUID字符串(please use ASSIGN_UUID)
ID_WORKER_STR 分布式全局唯一ID 字符串类型(please use ASSIGN_ID)

7.2. 增加

1
int insert(T entity);

7.3. 更新

1
2
3
4
// 根据 whereEntity 条件,更新记录
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);
// 根据 ID 修改
int updateById(@Param(Constants.ENTITY) T entity);

7.4. 查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 根据 ID 查询
T selectById(Serializable id);
// 根据 entity 条件,查询一条记录
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 查询(根据ID 批量查询)
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 entity 条件,查询全部记录
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 查询(根据 columnMap 条件)
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
// 根据 Wrapper 条件,查询全部记录
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 根据 entity 条件,查询全部记录(并翻页)
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录(并翻页)
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询总记录数
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

测试

1
2
3
4
5
6
7
8
9
10
11
12
// 查询所有
for(User u:userMapper.selectList(null)){
System.out.println(u);
}

//根据ID批量查询
userMapper.selectBatchIds(Arrays.asList(1,2,3));

//根据Map查询
HashMap<String,Object> map = new HashMap<>();
map.put("name","rose");
userMapper.selectByMap(map);

7.5. 删除

1
2
3
4
5
6
7
8
// 根据 entity 条件,删除记录
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
// 删除(根据ID 批量删除)
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 ID 删除
int deleteById(Serializable id);
// 根据 columnMap 条件,删除记录
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

8. 自动填充-更新时间

8.1. @TableField(fill = FieldFill.INSERT)

注解填充字段

1
2
3
4
5
@TableField(fill = FieldFill.INSERT) //添加数据时加值
private Date createTime;

@TableField(fill=FieldFill.INSERT_UPDATE) //修改数据时加值
private Date updateTime;

8.2. 实现类 MyMetaObjectHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.runaccpeted.mybatisplus.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;

//注册到容器中
@Component
class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
System.out.println(".......insert..........");
//strictInsertFill(MetaObject metaObject, String fieldName, Class<T> fieldType, Object fieldVal)
this.strictInsertFill(metaObject,"createTime", Date.class,new Date());
this.strictInsertFill(metaObject,"updateTime", Date.class,new Date());
}

@Override
public void updateFill(MetaObject metaObject) {
this.strictInsertFill(metaObject,"updateTime", Date.class,new Date());
}
}

8.3. 测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.runaccpeted.mybatisplus;

import com.runaccpeted.mybatisplus.entity.User;
import com.runaccpeted.mybatisplus.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Date;

@RunWith(SpringRunner.class)
@SpringBootTest
class MybatisplusApplicationTests {

@Autowired
UserMapper userMapper;

@Test
void contextLoads() {

User user = new User();
user.setName("rose");
user.setAge(90);
user.setEmail("yuyu@163.com");
userMapper.insert(user);
}

@Test
void update(){
User user = new User();
user.setId(1233034506639908866L);
user.setName("amy");
userMapper.updateById(user);
}

}

8.4. 输出

1
2
3
4
5
6
7
==>  Preparing: INSERT INTO user ( id, name, age, email, create_time, update_time ) VALUES ( ?, ?, ?, ?, ?, ? ) 
==> Parameters: 1233035752850354178(Long), rose(String), 90(Integer), yuyu@163.com(String), 2019-12-27 22:26:46.838(Timestamp), 2019-12-27 22:26:46.846(Timestamp)
<== Updates: 1

==> Preparing: UPDATE user SET name=?, update_time=? WHERE id=?
==> Parameters: amy(String), 2019-12-27 22:37:20.619(Timestamp), 1233034506639908866(Long)
<== Updates: 1

9. 乐观锁

丢失更新

当多个线程运行时,通过比较当前数据版本号和数据库里记录版本号是否一样,一致才提交事务,并把版本号+1。其他线程提交时,版本号不同则不能提交事务。

9.1. 表中添加版本号列

1
alter table user add column version int default 1;

9.2. 插件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.runaccpeted.mybatisplus.config;

import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MybatisplusConfig {
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}

9.3. 添加属性@Version

1
2
@Version
private Integer version;

9.4. 注意⚠️

支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
仅支持 updateById(id) 与 update(entity, wrapper) 方法

自动填充版本号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.runaccpeted.mybatisplus.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;

@Component
class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
//System.out.println(".......insert..........");
//strictInsertFill(MetaObject metaObject, String fieldName, Class<T> fieldType, Object fieldVal)
this.strictInsertFill(metaObject,"version", Integer.class,1);
}
}

9.5. 测试乐观锁

1
2
3
4
5
6
@Test
void update(){
User user = userMapper.selectById(1233005715855114242L);
user.setName("Alice");
userMapper.updateById(user);
}

9.6. 输出

1
2
3
4
5
6
7
8
9
10
==>  Preparing: SELECT id,name,age,email,create_time,update_time,version FROM user WHERE id=? 
==> Parameters: 1233005715855114242(Long)
<== Columns: id, name, age, email, create_time, update_time, version
<== Row: 1233005715855114242, tom, 80, wt@163.com, 2019-12-27 21:07:25, 2019-12-27 21:07:25, 1
<== Total: 1


==> Preparing: UPDATE user SET name=?, age=?, email=?, create_time=?, update_time=?, version=? WHERE id=? AND version=?
==> Parameters: Alice(String), 80(Integer), wt@163.com(String), 2019-12-27 21:07:25.0(Timestamp), 2019-12-27 23:44:34.459(Timestamp), 2(Integer), 1233005715855114242(Long), 1(Integer)
<== Updates: 1

10. 分页实现

10.1. 注册PaginationInterceptor Bean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.runaccpeted.mybatisplus.config;

import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@EnableTransactionManagement
@Configuration
@MapperScan(basePackages = "com.runaccpeted.mybatisplus.mapper")
public class MybatisplusConfig {
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}

//注册分页插件
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
return paginationInterceptor;
}
}

10.2. Page(long current, long size) - selectPage()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

@Test
void selPage(){

//public Page(long current, long size) {}
Page<User> page = new Page<>(1,3);
userMapper.selectPage(page,null);
System.out.println("当前页 "+page.getCurrent());
System.out.println("每页记录数 "+page.getSize());
System.out.println("总页数 "+page.getPages());
System.out.println("总记录数 "+page.getTotal());
System.out.println("有上一页 "+page.hasPrevious());
System.out.println("有下一页 "+page.hasNext());
System.out.println("当前记录 "+page.getRecords());
}

10.3. 输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
==>  Preparing: SELECT COUNT(1) FROM user 
==> Parameters:
<== Columns: COUNT(1)
<== Row: 8
==> Preparing: SELECT id,name,age,email,create_time,update_time,version FROM user LIMIT ?,?
==> Parameters: 0(Long), 3(Long)
<== Columns: id, name, age, email, create_time, update_time, version
<== Row: 1233005715855114242, Alice, 80, wt@163.com, 2019-12-27 21:07:25, 2019-12-27 21:27:25, 2
<== Row: 1233015547436777474, tom, 80, wt@163.com, 2019-12-27 21:07:29, 2019-12-27 21:07:29, 1
<== Row: 1233031811831980033, rose, 90, yuyu@163.com, 2019-12-27 21:08:29, 2019-12-27 21:08:29, 1
<== Total: 3
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4af45442]
当前页 1
每页记录数 3
总页数 3
总记录数 8
有上一页 false
有下一页 true
当前记录 [User(id=1233005715855114242, name=Alice, age=80, email=wt@163.com, createTime=Thu Feb 27 20:07:25 CST 2019, updateTime=Thu Feb 27 23:44:34 CST 2019, version=2), User(id=1233015547436777474, name=tom, age=80, email=wt@163.com, createTime=Thu Feb 27 21:07:29 CST 2019, updateTime=Thu Feb 27 21:07:29 CST 2019, version=1), User(id=1233031811831980033, name=rose, age=90, email=yuyu@163.com, createTime=Thu Feb 27 21:08:29 CST 2019, updateTime=Thu Feb 27 21:08:29 CST 2019, version=1)]

11. 逻辑删除

不同于物理删除,仍存在于数据库,状态改为被删除状态

11.1. 表中添加删除状态字段

1
alter table user add column deleted boolean default 0;

表中没有boolean属性

11.2. 实体类中添加属性@TableLogic

1
2
3
@TableLogic
@TableField(fill = FieldFill.INSERT)
private Integer deleted;

11.3. 自动填充状态

1
2
3
4
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject,"deleted",Integer.class,0);
}

11.4. 配置application.properties

1
2
3
4
5
6
# 逻辑已删除值(默认为 1)
mybatis-plus.global-config.db-config.logic-delete-value=1
# 逻辑未删除值(默认为 0)
mybatis-plus.global-config.db-config.logic-not-delete-value=0
# 全局逻辑删除字段值
mybatis-plus.global-config.db-config.logic-delete-field=true

11.5. 删除测试

1
2
3
4
5
@Test
void delete(){
userMapper.deleteById(1233033268573749250L);
//userMapper.delete(user);
}

11.6. 输出

1
2
3
==>  Preparing: UPDATE user SET deleted=1 WHERE id=? AND deleted=0 
==> Parameters: 1233033268573749250(Long)
<== Updates: 1

并没有删除这条记录

11.7. 查询测试

1
2
3
4
5
6
@Test
void selall(){
for(User u:userMapper.selectList(null)){
System.out.println(u);
}
}

11.8. 输出

1
2
3
4
==>  Preparing: SELECT id,name,age,email,create_time,update_time,version,deleted FROM user WHERE deleted=0 
==> Parameters:
<== Columns: id, name, age, email, create_time, update_time, version, deleted
<== Total: 8

输出的是deleted=0 的记录

12. 条件构造器Wrapper-QueryWrapper

https://mp.baomidou.com/guide/wrapper.html#alleq

12.1. gt(“age”,80) = age>80

1
2
3
4
5
6
7
8
9
10
@Test
void selByCondition(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
// age>80
wrapper.gt("age",80);

for (User u:userMapper.selectList(wrapper)) {
System.out.println(u);
}
}

12.1.1. 输出

1
==>  Preparing: SELECT id,name,age,email,create_time,update_time,version,deleted FROM user WHERE deleted=0 AND (age > ?) 

12.2. like(“name”,”王”) = name like ‘%王%’

12.3. select(“id”, “name”, “age”)  仅查询出几个字段数据

本文结束  感谢您的阅读
  • 本文作者: Wang Ting
  • 本文链接: /zh-CN/2019/12/27/MyBatis-Plus/
  • 发布时间: 2019-12-27 15:56
  • 更新时间: 2022-10-24 20:19
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!