来源公众号:赵侠客
一、Mybatis-plus基本功能
1.1 Mybatis-plus内置方法
Mybatis-plus
给我们造了很多轮子,让我们可以开箱即用,在BaseMapper
中有19种操作数据库常用的方法,如Insert()
、deleteById()
、updateById()
、selectById()
等。
我们在开发时只需要将我们的UserMapper
继承BaseMapper
就可以获取这些操作数据库的常用方法,不需要再重复写这些方法了,比较方便。
@Repository
public interface UserMapper extends BaseMapper<User> {
}
Mybatis-plus在IService
给我们提供了更多更为丰富的操作数据库的方法。我们在使用时只需要将我们的UserServiceImpl
继承ServiceImpl
并实现IService
接口就可轻松获取这些方法。
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IService {
}
1.2 存在的问题
Mybatis-plus
确实给我们提供了很多方法,同时也限制了我们的需求,比如我有一些很常见的需求:
-
逻辑删除数据时,将操作人记录到数据库中。 如果你使用
Mybatis-plus
的removeById(1L)
,这个方法只能将数据库逻辑位设置成删除状态,操作人是无法记录到数据库的。 -
每张表都有一个tenant_id,我想通过tenant_id把表中的id查出来,
Mybatis-plus
也没有一个selectIdByTenantId()
的方法。那我们只能每张表都写一个selectIdByTenantId
,代码确实有点冗余了。所以针对以上存在的问题,我们可以
Mybatis-plus
再增加点plus。
二、给BaseMapper增加几个plus
2.1 给BaseMapper增加点方法
Mybatis-plus
内置的方法都是承AbstractMethod
public class DeleteById extends AbstractMethod {
public DeleteById() {
super("deleteById");
}
}
所以我们可以写一个DeleteAndUpdateById
类然后仿照UpdateById
的写法将我们的实体中的字段更新到数据库的同时将逻辑删除位设置为删除状态。
public class DeleteAndUpdateById extends AbstractMethod {
/**
* 注入自定义 MappedStatement
* 根据id逻辑删除,顺带更新数据
*
* @param mapperClass mapper 接口
* @param modelClass mapper 泛型
* @param tableInfo 数据库表反射信息
* @return MappedStatement
*/
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
String methodName = CustomSqlMethod.DELETE_AND_UPDATE_BY_ID.getMethod();
String logicSql = CustomSqlMethod.DELETE_AND_UPDATE_BY_ID.getSql();
final String additional = optlockVersion(tableInfo) + tableInfo.getLogicDeleteSql(true, true);
logicSql = String.format(logicSql,
tableInfo.getTableName(),
sqlSet(false, false, tableInfo, false, ENTITY, ENTITY_DOT),
tableInfo.getKeyColumn(),
ENTITY_DOT + tableInfo.getKeyProperty(),
additional);
SqlSource sqlSource = languageDriver.createSqlSource(configuration, logicSql, modelClass);
return addUpdateMappedStatement(mapperClass, modelClass, methodName, sqlSource);
}
/**
* SQL 更新 set 语句
*
* @param logic 是否逻辑删除注入器
* @param ew 是否存在 UpdateWrapper 条件
* @param table 表信息
* @param judgeAliasNull
* @param alias 别名
* @param prefix 前缀
* @return sql
*/
@Override
protected String sqlSet(boolean logic, boolean ew, TableInfo table, boolean judgeAliasNull, String alias, String prefix) {
StringBuilder sqlScriptBuilder = new StringBuilder();
// 添加删除的sql
sqlScriptBuilder.append(table.getLogicDeleteSql(false, false))
.append(DOT_NEWLINE);
// 添加更新的sql
sqlScriptBuilder.append(table.getAllSqlSet(true, prefix));
String sqlScript = sqlScriptBuilder.toString();
if (judgeAliasNull) {
sqlScript = SqlScriptUtils.convertIf(sqlScript, String.format("%s != null", alias), true);
}
if (ew) {
sqlScript += NEWLINE;
sqlScript += convertIfEwParam(U_WRAPPER_SQL_SET, false);
}
sqlScript = SqlScriptUtils.convertSet(sqlScript);
return sqlScript;
}
}
然后我们需要将DeleteAndUpdateById
方法添加到DefaultSqlInjector
中。
@Component
public class CustomSqlInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
methodList.add(new DeleteAndUpdateById());
return methodList;
}
}
写个CustomBaseMapper
,继承BaseMapper
、再增加我们的deleteAndUpdateById
方法
public interface CustomBaseMapper<T> extends com.baomidou.mybatisplus.core.mapper.BaseMapper<T> {
/**
* 根据id做逻辑删除,并同时修改内容
*
* @param entity
* @return
*/
int deleteAndUpdateById(@Param(Constants.ENTITY) T entity);
}
最后将UserMapper
继承CustomBaseMapper
这样UserMappe
r就有了deleteAndUpdateById
方法了
@Repository
public interface UserMapper extends CustomBaseMapper<User> {
}
2.2 给ISerivce增加点方法
定义 ICustomService
方法继承IService
public interface ICustomService<T> extends IService<T> {
List<Long> selectByTenantIds(List<Long> tenantIds);
int deleteAndUpdateById(@Param(Constants.ENTITY) T entity);
}
然后创建CustomBaseServiceImpl
实现ICustomService
中的方法
public class CustomBaseServiceImpl<M extends CustomBaseMapper<T>, T extends BaseDomain> extends ServiceImpl<M, T> {
/**
* 删除并更新内容 根据ID
*
* @param entity 对象
* @return
*/
public int deleteAndUpdateById(T entity) {
return baseMapper.deleteAndUpdateById(entity);
}
public List<Long> selectByTenantIds(List<Long> tenantIds) {
QueryWrapper queryWrapper = new QueryWrapper<>();
queryWrapper.select("id");
queryWrapper.in(!tenantIds.contains(0L), "tenant_id", tenantIds);
return listObjs(queryWrapper, id -> Long.valueOf(id.toString()));
}
}
最后将我们的UserService
改成继承我们自己的ICustomService
、UserServiceImpl
public interface ICustomService<T> extends IService<T> {
List<Long> selectByTenantIds(List<Long> tenantIds);
int deleteAndUpdateById(@Param(Constants.ENTITY) T entity);
}
三、测试
3.1 测试方法
通过上面的改造,我们所有的Service都有了deleteAndUpdateById()
方法和selectByTenantIds()
方法。
class ApplicationTests {
@Resource
private UserService userService;
@Test
void testDeleteAndUpadteById() {
User user = userService.getById(1L);
user.setModifiedBy("赵侠客");
user.setModifiedAt(LocalDateTime.now());
userService.deleteAndUpdateById(user);
User dbUser = userService.getById(1L);
Assert.isTrue(dbUser == null, "删除成功");
}
@Test
void test() {
var userIds = userService.selectByTenantIds(List.of(1L));
log.info("userIds:{}", userIds);
Assert.isTrue(userIds != null);
}
}
四、总结
这里我只是给Mybatis-plus
增加了两个plus功能,更多的功能可以要根据自己的需求在CustomBaseMapper
和ICustomService
中添加就好了,主要可以扩展的Plus点有以下:
- 改写Mybatis-plus内置满足不了我们实际需求的方法
- 代码中很多通用的方法可以抽取成Plus公共功能
源码地址:https://gitee.com/whzhaochao/mybatis-plus-plus
原文地址:https://mp.weixin.qq.com/s/JnS9pmZvlvTvnutnpdYAwA