参考链接:mp.baomidou.com/guide
快速开始
- 1.用idea springinit 初始化ssm项目(tools:Lombok web:spring web )
- 2.pom中添加
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
- 3.在 Spring Boot 启动类中添加
@MapperScan 注解,扫描 Mapper 文件夹
@MapperScan("com.baomidou.mybatisplus.samples.quickstart.mapper")
import com.baomidou.mybatisplus.extension.service.IService;
public interface UserService extends IService<User> {
void export(UserExportDTO userExportDTO);
}
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface UserMapper extends BaseMapper<User> {
}
注解
| 属性 | 类型 | 默认值 | 描述 |
|---|
| value | String | "" | 表名 |
| autoResultMap | boolean | false | 是否自动构建 resultMap 并使用 |
autoResultMap: true 需要配合非xml等才能生效
如下代码
@Data
@TableName(value = "user_info", autoResultMap = true)
public class User{
@TableId(type = IdType.AUTO)
private Integer id;
private String name;
private String gender;
private String age;
@TableField(typeHandler = JacksonTypeHandler.class)
private List<String> roleIds;
private Date joinDate;
}
作用等同于之前xml里面这样实现 ,出表时的role_ids parse成想要的类型,而入表时能toJson转成字符类型
<resultMap id="getUserById" type="com.my.demo.model.entity.User">
<result column="role_ids" property="roleIds" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"></result>
</resultMap>
<select id="getUserById" resultMap="getUserById">
select * from user_info where id = #{id}
</select>
| 属性 | 类型 | 默认值 | 描述 |
|---|
| value | String | "" | 表中字段名,默认会下划线转成小驼峰 |
| exist | boolean | true | 当这个属性不为表中字段时,需要设置为true |
| insertStrategy | Enum | DEFAULT | 当插入整个实体时,默认 或者 为FieldStrategy.NOT_NULL ,则实体属性为null判定为不插入;当为FieldStrategy.IGNORED,即使实体某个属性为null也会插入表中 |
| updateStrategy | Enum | DEFAULT | 同insertStrategy。 |
| fill | Enum | FieldFill.DEFAULT | 字段自动填充策略,当为FieldFill.UPDATE 更新时填充;INSERT_UPDATE 插入更新时填充。需要配合字段填充拦截器使用 |
| typeHandler | Class<? extends TypeHandler> | UnknownTypeHandler.class | 类型处理器 ,应用场景: set 入表时对字段的操作,譬如加密; get 出表时对字段的操作,譬如解密 |
条件构造器
eq(R column, Object val)
eq(boolean condition, R column, Object val)
eq("name", "老王") ---> name = '老王'
ne(R column, Object val)
ne(boolean condition, R column, Object val)
ne("name", "老王") ---> name <> '老王'
```java
- gt ge lt le
```java
gt(R column, Object val)
gt(boolean condition, R column, Object val)
gt("age", 18) ---> age > 18
notBetween(R column, Object val1, Object val2)
notBetween(boolean condition, R column, Object val1, Object val2)
between("age", 18, 30) ---> age between 18 and 30
- like notLike likeLeft likeRight
like("name", "王" ) ---> name like '%王%'
likeLeft("name", "王" ) ---> name like '%王'
isNotNull(R column)
isNotNull(boolean condition, R column)
isNull("name")--->name is null
in("age",{1,2,3})--->age in (1,2,3)
inSql(R column, String inValue)
inSql(boolean condition, R column, String inValue)
inSql("id", "select id from table where id < 3") ---> id in (select id from table where id < 3)
groupBy(R... columns)
groupBy(boolean condition, R... columns)
groupBy("id", "name")--->group by id,name
- orderByAsc orderByDesc orderBy
orderByDesc(R... columns)
orderByDesc(boolean condition, R... columns)
orderBy(boolean condition, boolean isAsc, R... columns)
having(String sqlHaving, Object... params)
having(boolean condition, String sqlHaving, Object... params)
having("sum(age) > 10" )---> having sum(age) > 10
having("sum(age) > {0}", 11 )---> having sum(age) > 11
eq("id",1).or().eq("name","老王")--->id = 1 or name = '老王'
and(i -> i.eq("name", "李白").ne("status", "活着"))--->and (name = '李白' and status <> '活着')
apply(String applySql, Object... params)
apply(boolean condition, String applySql, Object... params)
当一般的条件无法满足时使用apply,
譬如
select * from "user_info" where jsonb_exists_all(role_ids, array ['88']) ;
apply("jsonb_exists_all(role_ids, array [{0}])", "\'88\'")
过滤
exists(String existsSql)
exists(boolean condition, String existsSql)
例如:table1作为主表查询,这时还需要筛选出满足 table2.dept_code in (1,2,3) 这个条件的数据才返回出去
exists (select id from table2 where table2.id = table1.id and table2.dept_code in (1,2,3))
常见写法
public interface UserService extends IService<User> {
void userUpdate(UserDTO userDTO);
UserBO userGet(UserDTO userDTO);
}
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
public interface UserMapper extends BaseMapper<User> {
}
User user = lambdaQuery().eq(User::getId, userDTO.getId()).one();
List<User> list = lambdaQuery().eq(User::getId, userDTO.getId()).list();
lambdaUpdate().eq(User::getId, userDTO.getId()).set(User::getName,userDTO.getName()).update();
save() / saveOrUpdate() / remove() / removeById() / update() / updateById()
wrapper 和 xml 混用
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(User::getId, userDTO.getId());
User user = getBaseMapper().getUser(queryWrapper, userDTO);
User getUser(@Param(Constants.WRAPPER) QueryWrapper<User> wrapper, @Param("userDTO") UserDTO userDTO);
<select id="getUser" resultType="com.my.demo.model.entity.User">
select * from user_info where
name = #{userDTO.name}
and ${ew.sqlSegment}
</select>
分页插件
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
}
Page<User> userPage = this.getBaseMapper().selectPage(new Page<>(2, 2), null);
自动填充功能
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
private static final String UPDATEDDATE = "updatedDate";
@Override
public void insertFill(MetaObject metaObject) {
log.info("insertFill....");
if (metaObject.hasGetter(UPDATEDDATE)) {
Object updatedDate = getFieldValByName(UPDATEDDATE, metaObject);
if (updatedDate == null) {
setFieldValByName(UPDATEDDATE, new Date(), metaObject);
}
}
}
@Override
public void updateFill(MetaObject metaObject) {
if (metaObject.hasGetter(UPDATEDDATE)) {
metaObject.setValue(UPDATEDDATE, null);
this.fillStrategy(metaObject, UPDATEDDATE, new Date());
}
}
}
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updatedDate;
批量插入的注意事项
发现MySQL JDBC驱动默认情况下会无视executeBatch()语句,会把批量语句拆散一条一条的发给数据库执行,批量插入实际上是单条插入,直接造成较低的性能。
解决方式
数据库连接参数配置了 rewriteBatchedStatements=true 最终得以解决
List<List<String>> newList = Lists.partition(oldList, 500);
newList.forEach(list -> {
});
逻辑删除
- 查找: 追加 where 条件过滤掉已删除数据,且使用 wrapper.entity 生成的 where 条件会忽略该字段
- 更新: 追加 where 条件防止更新到已删除数据,且使用 wrapper.entity 生成的 where 条件会忽略该字段
- 删除: 转变为 更新
@TableLogic
private Integer deleted;
- 删除: `update user set deleted=1 where id = 1 and deleted=0`
- 查找: `select id,name,deleted from user where deleted=0`
批量插入或更新
saveOrUpdateBatch(users);
QueryWrapper 的粘性
wrapper有粘性,为了避免循环中wrapper残留上次的条件,需要循环开始时,初始化wrapper
- 必要时 初始化wrapper 或者 clone() 或者 clear()
private List<User> queryByUserId(List<String> ids, QueryWrapper<User> wrapper){
List<User> users = new ArrayList<>();
Lists.partition(ids, 500).forEach(idPartition -> {
QueryWrapper<User> wrapperClone = wrapper.clone();
users.addAll(list(wrapperClone.lambda()
.select(User::getId, User::getName)
.in(User::getId, idPartition)));
});
return users;
}