SpringBoot整合mybatis-plus

官网:MyBatis-Plus

依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.1</version>
</dependency>

配置

配置 MapperScan 注解


@SpringBootApplication
@MapperScan("com.mybatisplus.mapper")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

配置application.yml

mybatis-plus:
  mapper-locations: classpath:mapper/*.xml
  configuration:
    map-underscore-to-camel-case: true
    auto-mapping-behavior: full
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  # 逻辑删除配置
  global-config:
    db-config:
      logic-delete-value: 1
      logic-not-delete-value: 0

其他参数参照:基本配置

使用

实体类


@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "user")//和实体类名不一致
public class User {
    //标记该属性为主键。value:属性名和列名不一样
    @TableId(value = "id")
    private Integer id;
    @TableField(value = "name")
    private String name;
 
    private Integer age;
 
    private String email;
}

注解

@TableName

表名注解,标识实体类对应的表,用在实体类上。

属性

类型

必须指定

默认值

描述

value

String

""

表名

schema

String

""

schema

keepGlobalPrefix

boolean

false

是否保持使用全局的 tablePrefix 的值(当全局 tablePrefix 生效时)

resultMap

String

""

xml 中 resultMap 的 id(用于满足特定类型的实体类对象绑定)

autoResultMap

boolean

false

是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建与注入)

excludeProperty

String[]

{}

需要排除的属性名 @since 3.3.1

@TableId

实体类主键字段

属性

类型

必须指定

默认值

描述

value

String

""

主键字段名

type

Enum

IdType.NONE

指定主键类型

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 方法)

@TableField

字段注解(非主键)

属性

类型

必须指定

默认值

描述

value

String

""

数据库字段名

exist

boolean

true

是否为数据库表字段

condition

String

""

字段 where 实体查询比较条件,有值设置则按设置的值为准,没有则为默认全局的 %s=#{%s}

update

String

""

字段 update set 部分注入,例如:当在version字段上注解update="%s+1" 表示更新时会 set version=version+1 (该属性优先级高于 el 属性)

insertStrategy

Enum

FieldStrategy.DEFAULT

举例:NOT_NULL

insert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>)

updateStrategy

Enum

FieldStrategy.DEFAULT

举例:IGNORED

update table_a set column=#{columnProperty}

whereStrategy

Enum

FieldStrategy.DEFAULT

举例:NOT_EMPTY

where <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if>

fill

Enum

FieldFill.DEFAULT

字段自动填充策略

select

boolean

true

是否进行 select 查询

keepGlobalFormat

boolean

false

是否保持使用全局的 format 进行处理

jdbcType

JdbcType

JdbcType.UNDEFINED

JDBC 类型 (该默认值不代表会按照该值生效)

typeHandler

Class<? extends TypeHandler>

UnknownTypeHandler.class

类型处理器 (该默认值不代表会按照该值生效)

numericScale

String

""

指定小数点后保留的位数

FieldStrategy

描述

IGNORED

忽略判断

NOT_NULL

非 NULL 判断

NOT_EMPTY

非空判断(只对字符串类型字段,其他类型字段依然为非 NULL 判断)

DEFAULT

追随全局配置

NEVER

不加入SQL

FieldFill

描述

DEFAULT

默认不处理

INSERT

插入时填充字段

UPDATE

更新时填充字段

INSERT_UPDATE

插入和更新时填充字段

@Version

乐观锁注解、标记 @Version 在字段上

@EnumValue

普通枚举类注解(注解在枚举字段上)

@TableLogic

表字段逻辑处理注解(逻辑删除)

属性

类型

必须指定

默认值

描述

value

String

""

逻辑未删除值

delval

String

""

逻辑删除值

@KeySequence

序列主键策略 oracle

属性

类型

必须指定

默认值

描述

value

String

""

序列名

dbType

Enum

DbType.OTHER

数据库类型,未配置默认使用注入 IKeyGenerator 实现,多个实现必须指定

@InterceptorIgnore

value 值为 1 | yes | on 视为忽略,例如 @InterceptorIgnore(tenantLine = "1")

value 值为 0 | false | off | 空值不变 视为正常执行。

@OrderBy

内置 SQL 默认指定排序,优先级低于 wrapper 条件查询

属性

类型

必须指定

默认值

描述

isDesc

boolean

true

是否倒序查询

sort

short

Short.MAX_VALUE

数字越小越靠前

Service CRUD 接口

参考官网接口,官网:CRUD 接口

save

boolean save(T entity);// 插入一条记录(选择字段,策略插入)

boolean saveBatch(Collection<T> entityList);// 插入(批量)

boolean saveBatch(Collection<T> entityList, int batchSize);// 插入(批量)

saveOrUpdate

boolean saveOrUpdate(T entity);// TableId 注解属性值存在则更新记录,否插入一条记录

boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper);// 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法

boolean saveOrUpdateBatch(Collection<T> entityList);// 批量修改插入

boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);// 批量修改插入

remove

boolean remove(Wrapper<T> queryWrapper);// 根据 queryWrapper 设置的条件,删除记录

boolean removeById(Serializable id);// 根据 ID 删除

boolean removeByMap(Map<String, Object> columnMap);// 根据 columnMap 条件,删除记录

boolean removeByIds(Collection<? extends Serializable> idList);// 删除(根据ID 批量删除)

update

boolean update(Wrapper<T> updateWrapper);// 根据 UpdateWrapper 条件,更新记录 需要设置sqlset

boolean update(T updateEntity, Wrapper<T> whereWrapper);// 根据 whereWrapper 条件,更新记录

boolean updateById(T entity);// 根据 ID 选择修改

boolean updateBatchById(Collection<T> entityList);// 根据ID 批量更新

boolean updateBatchById(Collection<T> entityList, int batchSize);// 根据ID 批量更新

get

T getById(Serializable id);// 根据 ID 查询

T getOne(Wrapper<T> queryWrapper);// 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")

T getOne(Wrapper<T> queryWrapper, boolean throwEx);// 根据 Wrapper,查询一条记录

Map<String, Object> getMap(Wrapper<T> queryWrapper);// 根据 Wrapper,查询一条记录

<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);// 根据 Wrapper,查询一条记录

list

List<T> list();// 查询所有

List<T> list(Wrapper<T> queryWrapper);// 查询列表

Collection<T> listByIds(Collection<? extends Serializable> idList);// 查询(根据ID 批量查询)

Collection<T> listByMap(Map<String, Object> columnMap);// 查询(根据 columnMap 条件)

List<Map<String, Object>> listMaps();// 查询所有列表

List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);// 查询列表

List<Object> listObjs();// 查询全部记录

<V> List<V> listObjs(Function<? super Object, V> mapper);// 查询全部记录

List<Object> listObjs(Wrapper<T> queryWrapper);// 根据 Wrapper 条件,查询全部记录

<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);// 根据 Wrapper 条件,查询全部记录

page

IPage<T> page(IPage<T> page);// 无条件分页查询

IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);// 条件分页查询

IPage<Map<String, Object>> pageMaps(IPage<T> page);// 无条件分页查询

IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);// 条件分页查询

count

int count();// 查询总记录数

int count(Wrapper<T> queryWrapper);// 根据 Wrapper 条件,查询总记录数

long count();// 查询总记录数(自3.4.3.2开始,返回值修改为long

long count(Wrapper<T> queryWrapper);// 根据 Wrapper 条件,查询总记录数

1、service接口-继承Iservice


public interface IUserService extends IService<User> {
}

2、接口实现类


@Service
public class IUserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
}

Mapper CRUD 接口

insert

int insert(T entity);// 插入一条记录

delete

int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);// 根据 entity 条件,删除记录

int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);// 删除(根据ID 批量删除)

int deleteById(Serializable id);// 根据 ID 删除

int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);// 根据 columnMap 条件,删除记录

update

int update(@Param(Constants.ENTITY) T updateEntity, @Param(Constants.WRAPPER) Wrapper<T> whereWrapper);// 根据 whereWrapper 条件,更新记录

int updateById(@Param(Constants.ENTITY) T entity);// 根据 ID 修改

select

T selectById(Serializable id);// 根据 ID 查询

T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);// 根据 entity 条件,查询一条记录

List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);// 查询(根据ID 批量查询)

List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);// 根据 entity 条件,查询全部记录

List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);// 查询(根据 columnMap 条件)

List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);// 根据 Wrapper 条件,查询全部记录

List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);// 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值

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

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

Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);// 根据 Wrapper 条件,查询总记录数

参考

MyBatis-Plus 之selectMaps、selectObjs、selectCount、selectOne的使用 - Python技术站



MyBatis-Plus 之selectMaps、selectObjs、selectCount、selectOne的使用_java_脚本之家


//BaseMapper接口中提供了单表的所有操作,连表不行,需要自己实现
@Repository
public interface UserMapper extends BaseMapper<User> {
}
 

扩展使用

QueryWrapper与LambdaQueryWrapper

使用condition组装条件
boolean condition:用于指定当前这个条件是否有效;如果为 true,则使用当前条件;如果为 false,则忽略当前条件。

参考

【java】Maybatis-Plus 数据库查询 lambdaQuery和mapper中EQ、NE、GT、LT、GE、LE、select、like、in、leftjoin的用法及详解_mybatisplus的ne_svt_井木的博客-CSDN博客

QueryWrapper 是的列名匹配使用的是数据库中的字段名
LambdaQueryWrapper 的列名匹配使用的是“Lambda的语法,偏向于对象”,不用写死字段名

方法简介使用范围普通 Wrapper示例Lambda Wrapper示例对应sql
allEq通过一个 Map 来设置多个字段的相等条件QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapperqueryWrapper.allEq(Map.of("name", "老王", "age", null));
lambdaQueryWrapper.allEq(Map.of( "name", "老王", "age", null));
WHERE name = '老王' AND age IS NULL
eq相等QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapperqueryWrapper.eq("name", "老王");lambdaQueryWrapper.eq(User::getName, "老王");WHERE name = '老王'
ne不相等QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapper
queryWrapper.ne("name", "老王");
lambdaQueryWrapper.ne(User::getName, "老王");WHERE name <> '老王'
gt大于 >QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapper
queryWrapper.gt("age", 18);
lambdaQueryWrapper.gt(User::getAge, 18);WHERE age > 18
ge大于等于 >=QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapperqueryWrapper.ge("age", 18);lambdaQueryWrapper.ge(User::getAge, 18);WHERE age >= 18
lt小于 <QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapperqueryWrapper.lt("age", 18);lambdaQueryWrapper.lt(User::getAge, 18);WHERE age < 18
le小于等于 <=QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapperqueryWrapper.le("age", 18);lambdaQueryWrapper.le(User::getAge, 18);WHERE age <= 18
between区间查询QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapperqueryWrapper.between("age", 18, 30);lambdaQueryWrapper.between(User::getAge, 18, 30);WHERE age BETWEEN 18 AND 30
notBetween不在区间范围QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapperqueryWrapper.notBetween("age", 18, 30);lambdaQueryWrapper.notBetween(User::getAge, 18, 30);WHERE age NOT BETWEEN 18 AND 30
like模糊匹配(左模糊 likeRight 、右模糊likeLeft) QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapperqueryWrapper.like("name", "王");lambdaQueryWrapper.like(User::getName, "王");WHERE name LIKE '%王%'
notLike不包含QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapperqueryWrapper.notLike("name", "王");lambdaQueryWrapper.notLike(User::getName, "王");WHERE name NOT LIKE '%王%'
isNullQueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapperqueryWrapper.isNull("name");lambdaQueryWrapper.isNull(User::getName);WHERE name IS NULL
in多个条件等于QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapperqueryWrapper.in("age", Arrays.asList(1, 2, 3));lambdaQueryWrapper.in(User::getAge, Arrays.asList(1, 2, 3));WHERE age IN (1, 2, 3)
notIn多个条件不等于QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapperqueryWrapper.notIn("age", Arrays.asList(1, 2, 3));lambdaQueryWrapper.notIn(User::getAge, Arrays.asList(1, 2, 3));WHERE age NOT IN (1, 2, 3)
inSqlin查询,可以添加sqlQueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapperqueryWrapper.inSql("age", "1,2,3,4,5,6");lambdaQueryWrapper.inSql(User::getAge, "1,2,3,4,5,6"); WHERE age IN (1, 2, 3, 4, 5, 6)
notInSql不属于,可添加sqlQueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapperqueryWrapper.notInSql("age", "1,2,3,4,5,6");
queryWrapper.notInSql("id", "select id from other_table where id < 3");
lambdaQueryWrapper.notInSql(User::getAge, "1,2,3,4,5,6");
lambdaQueryWrapper.notInSql(User::getId, "select id from other_table where id < 3");
WHERE age NOT IN (1, 2, 3, 4, 5, 6)
WHERE id NOT IN (select id from other_table where id < 3)
eqSql 字段等于sql结果(版本3.5.6)QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapperqueryWrapper.eqSql("id", "select MAX(id) from table");lambdaQueryWrapper.eqSql(User::getId, "select MAX(id) from table");WHERE id = (select MAX(id) from table)
groupBy分组QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapperqueryWrapper.groupBy("id", "name");lambdaQueryWrapper.groupBy(User::getId,User::getName);group by id,name
orderByAsc排序-升序QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapperqueryWrapper.orderByAsc("id", "name");lambdaQueryWrapper.orderByAsc(User::getId,User::getName);order by id asc, name asc
orderByDesc排序-降序QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapperqueryWrapper.orderByDesc("id", "name");lambdaQueryWrapper.orderByDesc(User::getId,User::getName);order by id desc, name  desc
orderBy排序QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapperqueryWrapper.orderBy(true, true, "id", "name");lambdaQueryWrapper.orderBy(true, true, User::getId, User::getName);order by id asc, name asc
having对分组后的数据进行条件筛选QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapper
queryWrapper.groupBy("age").having("sum(age) > 10");
lambdaQueryWrapper.groupBy(User::getAge).having("sum(age) > {0}", 10);
GROUP BY age HAVING sum(age) > 10
func构建查询条件QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapperqueryWrapper.func(i -> {
 if (true) {
  i.eq("id", 1);
 } else {
  i.ne("id", 1);
 }
});
lambdaQueryWrapper.func(i -> {
 if (true) {
  i.eq(User::getId, 1);
 } else {
  i.ne(User::getId, 1);
 }
});
如果条件为 true
SELECT * FROM user WHERE id = 1
如果条件为 false
SELECT * FROM user WHERE id != 1
orQueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapper
queryWrapper.eq("id", 1).or().eq("name", "老王");
嵌套
queryWrapper.or(i -> i.and(j -> j.eq("name", "李白").eq("status", "alive"))
.or(j -> j.eq("name", "杜甫").eq("status", "alive")));
lambdaQueryWrapper.eq(User::getId, 1).or().eq(User::getName, "老王");
嵌套
lambdaQueryWrapper.or(i -> i.and(j -> j.eq(User::getName, "李白").eq(User::getStatus, "alive"))
.or(j -> j.eq(User::getName, "杜甫").eq(User::getStatus, "alive")));
WHERE id = 1 OR name = '老王'
嵌套
WHERE (name = '李白' AND status = 'alive') OR (name = '杜甫' AND status = 'alive')
andQueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapperqueryWrapper.and(i -> i.and(j -> j.eq("name", "李白").eq("status", "alive"))
.and(j -> j.eq("name", "杜甫").eq("status", "alive")));
lambdaQueryWrapper.and(i -> i.and(j -> j.eq(User::getName, "李白").eq(User::getStatus, "alive"))
.and(j -> j.eq(User::getName, "杜甫").eq(User::getStatus, "alive")));
WHERE (name = '李白' AND status <> '活着')
nested查询条件块QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapper
queryWrapper.nested(i -> i.eq("name", "李白").ne("status", "活着"));
lambdaQueryWrapper.nested(i -> i.eq(User::getName, "李白").ne(User::getStatus, "活着"));
 WHERE (name = '李白' AND status <> '活着')
apply自定义查询条件QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapper
queryWrapper.apply("id = 1");
queryWrapper.apply("date_format(dateColumn, '%Y-%m-%d') = {0}", "2008-08-08");
lambdaQueryWrapper.apply("date_format(dateColumn, '%Y-%m-%d') = '2008-08-08'");
WHERE id = 1
WHERE date_format(dateColumn, '%Y-%m-%d') = '2008-08-08'
last查询语句最后添加sql片段QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapperqueryWrapper.last("limit 1");lambdaQueryWrapper.last("limit 1");LIMIT 1
exists添加子查询QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapper
queryWrapper.exists("select id from table where age = 1");
lambdaQueryWrapper.exists("select id from table where age = 1");
WHERE EXISTS (select id from table where age = 1)
notExists与exists相反QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrapperqueryWrapper.notExists("select id from table where age = 1");lambdaQueryWrapper.notExists("select id from table where age = 1");WHERE NOT EXISTS (select id from table where age = 1)
select查询字段QueryWrapper、LambdaQueryWrapperqueryWrapper.select("id", "name", "age");
lambdaQueryWrapper.select(User::getId, User::getName, User::getAge);
SELECT id, name, age FROM user
set更新语句,set字段UpdateWrapper、LambdaUpdateWrapperupdateWrapper.set("name", "老李头");lambdaUpdateWrapper.set(User::getName, "老李头");UPDATE user SET name = '老李头'
setSql更新语句,sql语句QueryWrapper、LambdaQueryWrapper、UpdateWrapper、LambdaUpdateWrappersetSql("name = '老李头'")
setSql("dateColumn={0}", LocalDate.now())
setSql("type={0,javaType=int,jdbcType=NUMERIC,typeHandler=xxx.xxx.MyTypeHandler}", "待处理字符串");
  
setIncrBy数值增加指定数值(版本3.5.6)UpdateWrapper、LambdaUpdateWrapper
updateWrapper.setIncrBy(Product::getNum, 1);
lambdaUpdateWrapper.setIncrBy(Product::getNum, 1);UPDATE product SET num = num + 1
setDecrBy数值减少指定值(版本>= 3.5.6)UpdateWrapper、LambdaUpdateWrapper
updateWrapper.setDecrBy("num", 1);
lambdaUpdateWrapper.setDecrBy(Product::getNum, 1);
UPDATE product SET num = num - 1
lambdaLambda表达式QueryWrapper、UpdateWrapperQueryWrapper调用lambda返回LambdaQueryWrapper。
UpdateWrapper调用lambda返回LambdaUpdateWrapper。
  

使用limit

// 查询单条
Article article = articleService.lambdaQuery().last("limit 1").one();
// 查询多条
List<Teacher> list = teacherService.lambdaQuery().last("limit 5").list();

去重

new QueryWrapper<T>().select("DISTINCT user_id");

自动填充功能

注解填充字段 @TableField(.. fill = FieldFill.INSERT)


public class User {
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
    ....
}

@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        this.setFieldValByName("createTime", new Date(), metaObject);
        this.setFieldValByName("updateTime", new Date(), metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
    }
}

根据指定字段更新或插入

自带的saveOrUpdate()方法,默认情况下根据主键是否存在进行更新或插入操作

public boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper) {
    return this.update(entity, updateWrapper) || this.saveOrUpdate(entity);
}

使用

// 创建UpdateWrapper指定查询条件
UpdateWrapper<User> updateWrapper = Wrappers.query();
updateWrapper .eq("name", 123);  
// 调用saveOrUpdate传入实体对象和UpdateWrapper对象
userMapper.saveOrUpdate(user, updateWrapper );

参考:

https://blog.csdn.net/u012288582/article/details/135091100

雪花算法

mybatis-plus默认雪花算法生成分布式唯一id

在分布式场景下,如果多台机器上的服务都指定相同的datacenterId和workerId,在高并发请求下,会出现Id重复的风险。
如下:
https://blog.csdn.net/wagnteng/article/details/117064242
现象:
出现重复的部署架构是单服务集群的部署方式
分析:
单机跑,压到1000的并发都没有出现过id重复,这个说明单机情况下不存在id重复问题,说明只有集群的情况下才会出现。
雪花算法的核心能影响到id生成的几个因素:1.服务器时间;2.workId(机器 ID 部分);3.datacenterId(数据标识 ID 部分)。
在服务器时间一样的情况下,有可能是由于两台机的虚拟机名称一样
解决:
mybatis-plus框架会根据应用所在服务器IP地址来生成datacenterId和workerId。
# 设置随机

mybatis-plus.global-config.worker-id: ${random.int(1,31)}
mybatis-plus.global-config.datacenter-id: ${random.int(1,31)}

其他解决方式:
https://blog.csdn.net/w1014074794/article/details/125607205
引入idworker框架,通过zookeeper管理snowflake算法中workerId和dataCenterId的生成,保证其唯一性,避免出现id重复的情况。

 <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.2</version>
    </dependency>

    <dependency>
        <groupId>com.imadcn.framework</groupId>
        <artifactId>idworker</artifactId>
        <version>1.5.0</version>
    </dependency>

添加zookeeper配置

mybatis-plus.zookeeper.serverLists=127.0.0.1:2181

指定mybatis-plus的id生成器
@Configuration
public class IdAutoConfig {
    @Value("${mybatis-plus.zookeeper.serverLists}")
    private String zkServerLists;

    @Bean
    public IdentifierGenerator idGenerator() {
        return new ImadcnIdentifierGenerator(zkServerLists);
    }
}

数据库全局配置策略

https://blog.csdn.net/BKKBjams/article/details/125538459

查询策略whereStrategy,更新策略updateStrategy,和添加策略insertStrategy
IGNORED:忽略判断,所有字段都进行更新、插入和查询;
NOT_NULL(默认):只更新和插入非NULL值,也不在查询时考虑空值字段;
NOT_EMPTY:只更新和插入非NULL值且非空字符串,也不在查询时考虑空值字段;
NEVER:永远不进行更新、插入和查询;
DEFAULT:默认策略;
 

分页查询

参考

mybatis-plus分页查询三种方法_mybatisplus分页查询_李长渊哦的博客-CSDN博客

MybatisPlus自定义对象查询和分页方法_mybatis-plus mapper 自定义方法 page对象_LinMain_copy的博客-CSDN博客

配置类


@Configuration
public class MybatisPlusConfig {
    /**
     * 分页插件。如果你不配置,分页插件将不生效
     */
    @Bean
    public MybatisPlusInterceptor paginationInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 指定数据库方言为 MYSQL
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

// 旧版
@Configuration
public class MybatisPlusConfig {  
  @Bean
  public PaginationInterceptor paginationInterceptor() {
       PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
       // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求  默认false
       paginationInterceptor.setOverflow(false);
       // 设置最大单页限制数量,默认 500 条,-1 不受限制
       paginationInterceptor.setLimit(500);
       // 开启 count 的 join 优化,只针对部分 left join
       paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
       return paginationInterceptor;
     }
}
// 新版
@Configuration
public class MybatisPlusConfig {  
/**
  * (3.4以上版本使用)新的分页插件,一缓和二缓遵循mybatis的规则,
  * 需要设置 MybatisConfiguration#useDeprecatedExecutor = false
  * 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
   @Bean
   public MybatisPlusInterceptor mybatisPlusInterceptor() {
 
         MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
         //DbType.MYSQL改为自己需要连接的数据库类型
         interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
         return interceptor;
    }
}

调用通用方法-selectPage


QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.isNotNull("account");

// 创建分页对象(1表示第一页;4表示每页大小为4)
Page<User> page = new Page<>(1, 10);
Page<User> result = userMapper.selectPage(page, wrapper);
for(Usern user : result.getRecords()) {
   System.out.println(user);
}

自定义分页查询

如果返回类型是 IPage 则入参的 IPage 不能为null

如果想临时不分页,可以在初始化IPage时size参数传 <0 的值

service

public IPage<PlanVO> getMaintenancePlanList(PlanPageDTO PlanDTO) {
	IPage<PlanVO> page = new Page<>(PlanDTO.getPageNo(), PlanDTO.getPageSize());
	IPage<PlanVO> result = planMapper.queryPlanList(page, PlanVO);
	return result;
}

mapper

传递参数 Page即自动分页,必须放在第一位

IPage<PlanVO> queryPlanList(@Param("page") IPage<PlanVO> page,@Param("PlanDTO") PlanPageDTO PlanDTO);

xml

<select id="queryPlanList" resultType="com.entity.vo.PlanVO">
	select
	p.id as id,
	p.plan_code as planCode,
	p.plan_name as planName
	from plan p
	order by p.id desc
</select>

‌IPage与‌Page‌‌

‌IPage

是Mybatis-Plus中的分页结果集接口,提供了一系列的分页查询方法。该接口主要用于返回分页后的数据结果。用于封装分页查询的结果,它在查询执行后由框架或库填充并返回。

使用@Param注解来传递分页参数。
分页查询通过调用BaseMapper的selectPage方法,返回的是一个包含查询结果的列表‌。

‌Page‌:
是IPage接口的默认实现类,实现了IPage接口中的方法。在进行分页查询时定义分页查询的参数,通常会创建一个Page对象,并设置相关的分页参数。在MyBatis-Plus 2.0版本之后,推荐使用Page接口进行分页查询。

通过方法的参数直接传递分页参数,更加简洁方便。
分页查询通过调用BaseMapper的selectPage方法,返回的是一个IPage对象,包含查询结果以及分页信息‌

feign调用返回IPage对象时报错

错误Cannot construct instance of com.baomidou.mybatisplus.core.metadata.IPage
解决:

方案一
在feign调用时将返回IPage改为返回page

方案二
将分页信息序列化 加入相应的配置类
https://blog.csdn.net/qq_35705176/article/details/128101924

处理json数据

对象


@Data
@Accessors(chain = true)
@TableName(autoResultMap = true)
public class User {
    /**
     *  必须开启映射注解
     * @TableName(autoResultMap = true)
     * 以下两种类型处理器,二选一 也可以同时存在,
     * 选择对应的 JSON 处理器也必须存在对应 JSON 解析依赖包
     */
    @TableField(typeHandler = JacksonTypeHandler.class)
    // @TableField(typeHandler = FastjsonTypeHandler.class)
    private OtherInfo otherInfo;
}

集合

自定义处理器,继承 FastjsonTypeHandler ,重载parse方法


public class JSONTypeHandler extends FastjsonTypeHandler {
    private final Class<? extends Object> type;
 
    public JSONTypeHandler(Class<?> type) {
        super(type);
        this.type = type;
    }
 
    @Override
    protected List parse(String json) {
        return JSON.parseArray(json, type);
//        return JSON.parseObject(json, type);
    }
 
    @Override
    protected String toJson(Object obj) {
        return super.toJson(obj);
    }
}

实体类


@TableName(autoResultMap = true)
public class User {
    @TableField(typeHandler = JSONTypeHandler.class)
    private List<Address> address;
}

在对应的xml中新增typeHandler、javaType

<mapper namespace="com.mapper.UserMapper">
    <resultMap id="BaseResultMap" type="com.entiry.User">
        <result property="address" column="address" typeHandler="com.handler.JSONTypeHandler" javaType="com.entiry.Address"/>
    </resultMap>
</mapper>

 下划线驼峰转换

参考

mybatis-plus踩坑之下划线驼峰转换_mybatisplus下划线与驼峰_Echoo华地的博客-CSDN博客

在mybatis-plus中,默认开启了下滑线-驼峰转换

 可以通过配置文件修改

mybatis-plus.configuration.map-underscore-to-camel-case=true

批量新增

参考

1、【MyBatis-Plus】之批量插入_mybatisplus批量insert_王廷云的博客的博客-CSDN博客

​​​​​​2、MyBatis-plus 批量新增方法性能测试及优化学习_mybatisplus savebatch_找了一圈尾巴的博客-CSDN博客3、mybatis以及mybatisplus批量插入问题_mybatisplus 批量插入_又 欠的博客-CSDN博客
 

IService-saveBatch

自定义批量新增

pom

<!-- mybatis plus 与 springboot 整合的依赖 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.0</version>
</dependency>

<!-- mybatis plus extension 包含了 mybatis plus core -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-extension</artifactId>
    <version>3.4.0</version>
</dependency>

自定义SQL注入类

public class CustomSqlInjector extends DefaultSqlInjector {

    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
        // 获取父类SQL注入方法列表
        List<AbstractMethod> methodList = super.getMethodList(mapperClass);
        // 将批量插入方法添加进去
        methodList.add(new InsertBatchSomeColumn());
        return methodList;
    }

}

mybatis-plus配置类

@Configuration
public class MybatisPlusConfig {

    @Bean
    public CustomSqlInjector customSqlInjector() {
        return new CustomSqlInjector();
    }
}

扩展BaseMapper 

/**
 * 添加批量插入接口
 */
public interface CustomMapper<T> extends BaseMapper<T> {

    /**
     * 批量插入
     * @param entityList 实体列表
     * @return 影响行数
     */
    Integer insertBatchSomeColumn(Collection<T> entityList);

}

批量更新

参考

Mybatis-plus通过其他字段批量更新或新增_mybatisplus批量更新指定的字段_帅宇Yeah~的博客-CSDN博客mybatisplus 根据非主键字段批量更新内容_mybatis plus 非主键更新_白衣渡江-吕子明的博客-CSDN博客1、Mybatis-plus通过其他字段批量更新或新增_mybatisplus批量更新指定的字段_帅宇Yeah~的博客-CSDN博客

根据id更新

IService-updateBatchById、saveOrUpdateBatch

自定义更新

扩展BaseServiceImpl

public boolean updateBatchByQueryWrapper(final Collection<T> entityList, final Function<T, QueryWrapper> function) {
	entityList.forEach(BaseEntity::preUpdate);
	final int batchSize = 1000;
	final String sqlStatement = this.sqlStatement(SqlMethod.UPDATE);
	try (final SqlSession batchSqlSession = this.sqlSessionBatch()) {
		int i = 0;
		for (final T entity : entityList) {
			final Map<String, Object> map = new HashMap<String, Object>(1);
			map.put("ew", function.apply(entity));
			map.put("et", entity);
			batchSqlSession.update(sqlStatement, (Object)map);
			if (i >= 1 && i % batchSize == 0) {
				batchSqlSession.flushStatements();
			}
			++i;
		}
		batchSqlSession.flushStatements();
	}
	return true;
}

 使用

 Function<User, QueryWrapper> function = user -> {
	QueryWrapper<SpatialStructureNodeTag> queryWrapper = new QueryWrapper();
	queryWrapper.lambda().eq(User::getUserId, user.getUserId());
	return queryWrapper;
};
BaseServiceImpl.updateBatchByQueryWrapper(userList, function);

逻辑删除

参考

MyBatis Plus 逻辑删除_mybatisplus逻辑删除_我有一只肥螳螂的博客-CSDN博客

Mybatis Plus 3.x 注入逻辑删除 LogicSqlInjector 报错_mybatis-plus 3.5 没有 logicsqlinjector 了_拄杖忙学轻声码的博客-CSDN博客

3.x需要在配置类新增

@Bean
public ISqlInjector sqlInjector() {
	return new LogicSqlInjector();
}

 实体类

@ApiModelProperty("是否删除标识 0:未删除  1:删除")
@TableLogic(value = "0",delval = "1")
private int isDel;

表字段为数据库关键字

@TableField(value="`group`")
private String group;

不能更新空值字段

参考

Mybatis-Plus不能更新对象字段为空值问题解决_mybatisplus空值不更新_lgily-1225的博客-CSDN博客Mybatis-Plus更新对象时字段更新为空值的问题 - 知乎
 

Mybatis-Plus中字段的更新策略是通过FieldStrategy属性控制的。

在实体字段上,如果不通过@TableField注解指定字段的更新策略,字段默认的更新策略是FieldStrategy.DEFAULT,即跟随全局策略。而Mybatis-Plus的全局配置中,字段的默认更新策略是FieldStrategy.NOT_NULL,即进行空值判断,不对NULL值数据进行处理。

设置字段级别的更新策略

@TableField(updateStrategy = FieldStrategy.IGNORED)
private String email;

设置全局更新策略

mybatis-plus.global-config.db-config.update-strategy=ignored

代码生成器

旧版

参考

https://www.cnblogs.com/lv1024/p/16086460.html

依赖

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.1.2</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.2.0</version>
        </dependency>
        <!-- 模板引擎 -->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.0</version>
        </dependency>

配置代码

public class Code {
    public static void main(String[] args) {
        //需要构建一个 代码自动生成器 对象
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();
        //配置策略

        //1、全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "\\mybatis-plus\\src\\main\\java");
        gc.setAuthor("xxxx");
        gc.setOpen(false);
        gc.setFileOverride(false);  //是否覆盖
        gc.setServiceName("%sService"); //去Service的I前缀
        gc.setIdType(IdType.ID_WORKER);
        gc.setDateType(DateType.ONLY_DATE);
        gc.setSwagger2(true);
        mpg.setGlobalConfig(gc);

        //2、设置数据源
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://111.11.11.11:111/aaa?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("root");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);

        //3、包的配置
        PackageConfig pc = new PackageConfig();
        // pc.setModuleName("mybatis-plus");
        pc.setParent("com.test");
        pc.setEntity("pojo");
        pc.setMapper("mapper");
        pc.setService("service");
        pc.setController("controller");
        mpg.setPackageInfo(pc);

        //4、策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("plan");    //设置要映射的表名
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true);    //自动lombok
        strategy.setLogicDeleteFieldName("del_flag");
        //自动填充配置
        TableFill createTime = new TableFill("create_date", FieldFill.INSERT);
        TableFill updateTime = new TableFill("update_date", FieldFill.UPDATE);
        ArrayList<TableFill> tableFills = new ArrayList<>();
        tableFills.add(createTime);
        tableFills.add(updateTime);
        strategy.setTableFillList(tableFills);
        //乐观锁
        // strategy.setVersionFieldName("version");
        // strategy.setRestControllerStyle(true);
        // strategy.setControllerMappingHyphenStyle(true);     //localhost:8080/hello_id_2
        mpg.setStrategy(strategy);

        mpg.execute();  //执行代码构造器
    }
}

新版

        <!--mybatis-plus依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
        <!--MP代码生成器依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.5.1</version>
        </dependency>
        <!--模板引擎依赖-->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.3</version>
        </dependency>

代码

public class CodeGeneration {
    /**
     * 根据表名生成相应结构代码
     *
     * @param tableName 表名
     */
    public static void Generation(String serviceName, String parent, String dataURL, String username, String password, String author, String... tableName) {
        FastAutoGenerator.create(dataURL, username, password)
                .globalConfig(builder -> {
                    builder.author(author) // 设置作者
                            .enableSwagger()//启用swagger
                            .outputDir(serviceName + "\\src\\main\\java");//指定输出目录
                })
                .packageConfig(builder -> {
                    builder.entity("entities.entity")//实体类包名
                            .parent("com.xxx." + parent)//设置父包名
                            .controller("controller")//控制层包名
                            .mapper("dao")//mapper层包名
                            .service("service")//service层包名
                            .serviceImpl("service.impl")//service实现类包名
                            //自定义mapper.xml文件输出目录
                            .pathInfo(Collections.singletonMap(OutputFile.mapperXml, serviceName + "\\src\\main\\resources\\mapper"));
                })
                .strategyConfig(builder -> {
                    builder.addInclude(tableName) //设置要生成的表名
                            .addTablePrefix("xxx_")//设置表前缀过滤
                            .entityBuilder()
                            .enableLombok()// 开启lombok模型
                            .enableChainModel() // 开启链式模型
                            .naming(NamingStrategy.underline_to_camel)//数据表映射实体命名策略:默认下划线转驼峰underline_to_camel
                            .columnNaming(NamingStrategy.underline_to_camel)//表字段映射实体属性命名规则:默认null,不指定按照naming执行
                            .superClass("com.xx.xxx.xxx.BaseEntity")//添加父类
                            .addSuperEntityColumns("create_time","update_time") //添加父类公共字段
                            .idType(IdType.AUTO)//添加全局主键类型
                            .formatFileName("%s")//格式化实体名称,%s取消首字母I,
                            .mapperBuilder() // 开启生成mapper
                            .enableMapperAnnotation()//开启mapper注解
                            // .enableBaseResultMap()//启用xml文件中的BaseResultMap 生成
                            // .enableBaseColumnList()//启用xml文件中的BaseColumnList
                            .formatMapperFileName("%sMapper")//格式化Dao类名称
                            .formatXmlFileName("%sMapper")//格式化xml文件名称
                            .serviceBuilder() // 开启生成service
                            .formatServiceFileName("%sService")//格式化 service 接口文件名称
                            .formatServiceImplFileName("%sServiceImpl")//格式化 service 接口文件名称
                            .controllerBuilder() //开启controller生成
                            .enableRestStyle();
                }).execute();
    }

    public static void main(String[] args) {
        Generation("xxx-xxx-xxx",
                "com.xxx.xxx.xxxx",
                "jdbc:mysql://xxxx:xxx/xxxxx?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false",
                "xxxx",
                "xxxx",
                "xxx",
                "xxxxx1","xxxxx2");
    }
}

参考

Mybatis—Plus3.5.2代码自动生成_mybatisplus自动生成dao-CSDN博客

MyBatis-Plus代码生成器(最新版适合新手跟做)_mybatisplus代码自动生成器-CSDN博客

多数据源配置

依赖

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>3.5.0</version>
        </dependency>

配置文件

spring:
# 配置数据源信息
  datasource:
    dynamic:
      # 设置默认的数据源或者数据源组,默认值即为master
      primary: master
      # 严格匹配数据源,默认false.true未匹配到指定数据源时抛异常,false使用默认数据源
      strict: false
      datasource:
        master:
          url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false
          driver-class-name: com.mysql.cj.jdbc.Driver
          username: root
          password: 123456
        slave_1:
          url: jdbc:mysql://localhost:3306/mybatis_plus_1?characterEncoding=utf-8&useSSL=false
          driver-class-name: com.mysql.cj.jdbc.Driver
          username: root
          password: 123456

使用

DS注解既可以写在类上,也可以写在方法上,方法上的优先级高于类。

如果没有指定DS的属性值或者没有使用DS注解,就自动走master主库。

@DS("slave_1")//指定所操作的数据源
@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product>
implements ProductService {
}

参考:https://baijiahao.baidu.com/s?id=1754519454163819416&wfr=spider&for=pc

联表查询 

依赖,注意:需要 Mybatis-plus version >= 3.4.0

<!-- 引入mybatis-plus联表查询相关依赖项 -->
<!-- MVNW pom格式 -->
<dependency>
    <groupId>com.github.yulichang</groupId>
    <artifactId>mybatis-plus-join</artifactId>
    <version>1.2.4</version>
</dependency>

2、使用
mapper继承MPJBaseMapper (必选)
service继承MPJBaseService (可选)
serviceImpl继承MPJBaseServiceImpl (可选)

  • 方法

MPJBaseMapper继承BaseMapper,在原有的方法基础上又添加了以下方法:
        selectJoinOne 连表查询一条记录对象
        selectJoinList 连表查询返回命中记录对象集合
        selectJoinPage 连表分页查询对象集合
        selectJoinMap 连表查询一条记录返回Map
        selectJoinMaps 连表查询返回命中记录Map集合
        selectJoinMapsPage 连表分页查询返回Map集合
MPJBaseService 继承了IService,同样添加以上方法
MPJBaseServiceImpl 继承了ServiceImpl,同样添加了以上方法

  • 查询核心类

MPJLambdaWrapper和MPJQueryWrapper

方法:

selectAll() // 可以查全部参数;

select()    // 查询字段,一个括号内仅能查一个实体,如需要查询多个表的字段,将有多个select();

selectAs()  // 相当于取别名,为了数据表内字段名称和结果集实体名称一致;

leftJoin()  //联结多个表,将有多个leftJoin(),方法3个参数:联入表实体,联入表关系字段,原表关系字段;参数说明
第一个参数: 联入表实体,参与连表的实体类class
第二个参数: 连表的ON字段,这个属性必须是第一个参数实体类的属性
第三个参数: 参与连表的ON的另一个实体类属性
默认主表别名是t,其他的表别名以先后调用的顺序使用t1,t2,t3…

示例1

// 产品类
public class Product
// 厂商类 
public class Factory
// 产品关联厂商类
public class ProductVO


@Repository
public interface ProductMapper extends MPJBaseMapper<Product> {
 
}
// 联表查询
List<ProductVO> productList = productMapper.selectJoinList(ProductVO.class,
		new MPJLambdaWrapper<Product>()
				.select(Product::getCode, Product::getName)
				.selectAs(Factory::getCode, ProductVO::getFactoryCode)
				.selectAs(Factory::getName, ProductVO::getFactoryName)
				.leftJoin(Factory.class, Factory::getCode, Product::getFactoryCode)
);
-- 对应sql
SELECT 
    t.code,
    t.name,
    t1.factoryCode,
    t1.factoryName
FROM 
    product t 
    LEFT JOIN factory t1 ON t1.code = t.factoryCode 

示例2

// 用户类
public class User
// 用户联系方式类 
public class UserAddress
// 产品关联厂商类
public class Area

@Repository
public interface UserMapper extends MPJBaseMapper<User> {
 
}
// 联表查询
List<UserVO> userList = userMapper.selectJoinList(UserVO.class,
		new MPJLambdaWrapper<User>()
				.selectAll(User.class)
				.select(UserAddress::getTel)
				.selectAs(UserAddress::getAddress, UserVO::getUserAddress)
				.select(Area::getProvince, Area::getCity)
				.leftJoin(UserAddress.class, UserAddress::getUserId, User::getId)
				.leftJoin(Area.class, Area::getId, UserAddress::getAreaId)
				.eq(User::getId, 1)
				.like(UserAddress::getTel, "131")
				.gt(User::getId, 5)
);
-- 对应sql
SELECT 
    t.id,
    t.name,
    t.sex,
    t1.tel,
    t1.address AS userAddress,
    t2.province,
    t2.city 
FROM 
    user t 
    LEFT JOIN user_address t1 ON t1.user_id = t.id 
    LEFT JOIN area t2 ON t2.id = t1.area_id 
WHERE (
    t.id = ? 
    AND t1.tel LIKE ? 
    AND t.id > ?)

参考:

https://blog.csdn.net/ZGL_cyy/article/details/117199228

https://blog.csdn.net/weixin_70506521/article/details/130722631

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值