mybatisplus 的常用CRUD方法
众所周知,mybatisplus提供了强大的代码生成能力,他默认生成的常用的CRUD方法(例如插入、更新、删除、查询等)的定义,能够帮助我们节省很多体力劳动。
他的BaseMapper
中定义了这些常用的CRUD方法,我们在使用时,继承这个BaseMapper
类就默认拥有了这些能力。
如果我们的业务中,需要类似的通用Sql时,该如何实现呢?
是每个Mapper中都定义一遍类似的Sql吗?
显然这是最笨的一种方法。
此时我们可以借助mybatisplus
这个成熟框架,来实现我们想要的通用Sql。
扩展常用CRUD方法
新增一个通用sql
比如有一个这样的需求,项目中所有表或某一些表,都要执行一个类似的查询,如`SelectByErp`,那么可以这样实现。(这是一个最简单的sql实现,使用时可以根据业务需求实现更为复杂的sql:比如多租户系统自动增加租户id参数、分库分表系统增加分库分表字段条件判断)
定义一个
SelectByErp
类,继承AbstractMethod
类,并实现injectMappedStatement
方法定义sql方法名、sql模板、实现sql的拼接组装
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
|
/ * *
* 新增一个通用sql
* /
public class SelectByErp extends AbstractMethod {
/ / 需要查询的列名
private final String erpColumn = "erp" ;
/ / sql方法名
private final String method = "selectByErp" ;
/ / sql模板
private final String sqlTemplate = "SELECT %s FROM %s WHERE %s=#{%s} %s" ;
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
/ / 获取需要查询的字段名及属性名
TableFieldInfo erpFiled = getErpProperty(tableInfo);
/ / 拼接组装sql
SqlSource sqlSource = new RawSqlSource(configuration, String. format (sqlTemplate,
sqlSelectColumns(tableInfo, false),
tableInfo.getTableName(),
erpFiled.getColumn(), erpFiled.getProperty(),
tableInfo.getLogicDeleteSql(true, false)), Object . class );
return this.addSelectMappedStatementForTable(mapperClass, method, sqlSource, tableInfo);
}
/ * *
* 查询erp列信息
* /
private TableFieldInfo getErpProperty(TableInfo tableInfo) {
List <TableFieldInfo> fieldList = tableInfo.getFieldList();
TableFieldInfo erpField = fieldList.stream(). filter (filed - > filed.getColumn().equals(erpColumn)).findFirst().get();
return erpField;
}
|
3.定义一个sql注入器GyhSqlInjector
,添加SelectByErp
对象
1
2
3
4
5
6
7
8
9
10
11
|
/ / 需注入到spring容器中
@Component
public class GyhSqlInjector extends DefaultSqlInjector {
@Override
public List <AbstractMethod> getMethodList(Class<?> mapperClass) {
List <AbstractMethod> methodList = super .getMethodList(mapperClass);
/ / 增加 SelectByErp对象,程序启动后自动加载
methodList.add(new SelectByErp());
return methodList;
}
}
|
4.定义一个基础MapperGyhBaseMapper
,添加selectByErp
方法
1
2
3
4
5
6
|
/ * *
* 自定义的通用Mapper
* /
public interface GyhBaseMapper<T> extends BaseMapper<T> {
List <T> selectByErp(String erp);
}
|
5.应用中需要使用该SelectByErp
方法的表,都继承GyhBaseMapper
,那么这些表将都拥有了selectByErp
这个查询方法,程序启动后会自动为这些表生成该sql。
1
|
public interface XXXMapper extends GyhBaseMapper<XXXTable>
|
添加一个mybatisplus已有sql
1.mybatisplus 常用CRUD方法如最上图,这些方法已经默认会自动生成,但mybatisplus其实提供了更多的方法,如下图,只要我们在启动时添加进去,就可以使用了。
2.比如我想使用AlwaysUpdateSomeColumnById
方法,该方法可以在更新时只更新我需要的字段,不进行全字段更新。添加步骤如下。
3.定义一个sql注入器 ,如GyhSqlInjector
,添加AlwaysUpdateSomeColumnById
对象
1
2
3
4
5
6
7
8
9
10
|
@Component
public class GyhSqlInjector extends DefaultSqlInjector {
@Override
public List <AbstractMethod> getMethodList(Class<?> mapperClass) {
List <AbstractMethod> methodList = super .getMethodList(mapperClass);
/ / 添加 AlwaysUpdateSomeColumnById 对象
methodList.add(new AlwaysUpdateSomeColumnById());
return methodList;
}
}
|
4.定义一个基础Mapper 如GyhBaseMapper
,添加alwaysUpdateSomeColumnById
方法
1
2
3
4
5
6
|
/ * *
* 自定义的通用Mapper
* /
public interface GyhBaseMapper<T> extends BaseMapper<T> {
int alwaysUpdateSomeColumnById(@Param(Constants.ENTITY) T entity);
}
|
5.继承GyhBaseMapper
的其他Mapper,将自动拥有alwaysUpdateSomeColumnById
方法
1
2
3
4
5
6
|
/ * *
* 自定义的通用Mapper
* /
public interface GyhBaseMapper<T> extends BaseMapper<T> {
int alwaysUpdateSomeColumnById(@Param(Constants.ENTITY) T entity);
}
|
6.继承GyhBaseMapper
的其他Mapper,将自动拥有alwaysUpdateSomeColumnById
方法
编辑一个mybatisplus已有sql
1.如果想编辑一个mybatisplus已有sql,比如分库分表系统,执行updateById
操作时,虽然主键Id已确定,但目标表不确定,此时可能导致该sql在多张表上执行,造成资源浪费,并且分库分表字段不可修改,默认的updateById
不能用,需要改造。以下以shardingsphere
分库分表为例。
2.定义一个UpdateByIdWithSharding
类,继承UpdateById
类
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
public class UpdateByIdWithSharding extends UpdateById {
private String columnDot = "`" ;
private YamlShardingRuleConfiguration yamlShardingRuleConfiguration;
/ / 注入shardingsphere的分库分表配置信息
public UpdateByIdWithSharding(YamlShardingRuleConfiguration yamlShardingRuleConfiguration) {
this.yamlShardingRuleConfiguration = yamlShardingRuleConfiguration;
}
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
String tableName = tableInfo.getTableName();
/ / shardingsphere 分库分表配置信息
Map <String, YamlTableRuleConfiguration> tables = yamlShardingRuleConfiguration.getTables();
/ / 判断当前表是否设置了分表字段
if (tables.containsKey(tableName)) {
YamlTableRuleConfiguration tableRuleConfiguration = tables.get(tableName);
/ / 获取分表字段
String shardingColumn = tableRuleConfiguration.getTableStrategy().getStandard().getShardingColumn();
/ / 构建sql
boolean logicDelete = tableInfo.isLogicDelete();
SqlMethod sqlMethod = SqlMethod.UPDATE_BY_ID;
/ / 增加分表字段判断
String shardingAdditional = getShardingColumnWhere(tableInfo, shardingColumn);
/ / 是否判断逻辑删除字段
final String additional = optlockVersion() + tableInfo.getLogicDeleteSql(true, false);
shardingAdditional = shardingAdditional + additional;
String sql = String. format (sqlMethod.getSql(), tableInfo.getTableName(),
getSqlSet(logicDelete, tableInfo, shardingColumn),
tableInfo.getKeyColumn(), ENTITY_DOT + tableInfo.getKeyProperty(),
shardingAdditional);
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
return addUpdateMappedStatement(mapperClass, modelClass, sqlMethod.getMethod(), sqlSource);
} else {
return super .injectMappedStatement(mapperClass, modelClass, tableInfo);
}
}
/ * *
* where条件增加分表字段
* /
private String getShardingColumnWhere(TableInfo tableInfo, String shardingColumn) {
StringBuilder shardingWhere = new StringBuilder();
shardingWhere.append( " AND " ).append(shardingColumn).append( "=#{" );
shardingWhere.append(ENTITY_DOT);
TableFieldInfo fieldInfo = tableInfo.getFieldList().stream()
. filter (f - > f.getColumn().replaceAll(columnDot, StringUtils.EMPTY).equals(shardingColumn))
.findFirst().get();
shardingWhere.append(fieldInfo.getEl());
shardingWhere.append( "}" );
return shardingWhere.toString();
}
/ * *
* set 模块去掉分表字段
* /
public String getSqlSet(boolean ignoreLogicDelFiled, TableInfo tableInfo, String shardingColumn) {
List <TableFieldInfo> fieldList = tableInfo.getFieldList();
/ / 去掉分表字段的 set 设置,即不修改分表字段
String rmShardingColumnSet = fieldList.stream()
. filter (i - > ignoreLogicDelFiled ? !(tableInfo.isLogicDelete() && i.isLogicDelete()) : true)
. filter (i - > !i.getColumn().equals(shardingColumn))
. map (i - > i.getSqlSet(ENTITY_DOT))
. filter (Objects::nonNull).collect(joining(NEWLINE));
return rmShardingColumnSet;
}
}
|
3.定义一个sql注入器GyhSqlInjector
,添加UpdateByIdWithSharding
对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
/ / 需注入到spring容器中
@Component
public class GyhSqlInjector extends DefaultSqlInjector {
/ * *
* shardingsphere 配置信息
* /
@Autowired
private YamlShardingRuleConfiguration yamlShardingRuleConfiguration;
@Override
public List <AbstractMethod> getMethodList(Class<?> mapperClass) {
List <AbstractMethod> methodList = super .getMethodList(mapperClass);
/ / 添加 UpdateByIdWithSharding 对象,并注入分库分表信息
methodList.add(new UpdateByIdWithSharding(yamlShardingRuleConfiguration));
return methodList;
}
}
|
4.定义一个基础MapperGyhBaseMapper
,添加新的selectById
方法
1
2
3
4
5
6
|
/ * *
* 自定义的通用Mapper
* /
public interface GyhBaseMapper<T> extends BaseMapper<T> {
int updateById(@Param(Constants.ENTITY) T entity);
}
|
5.所有参与分表的表,在定义Mapper时继承GyhBaseMapper
,那么在使用他的updateById
方法时,将自动增加分库分表判断,准确命中目标表,减少其他分表查询的资源浪费。
以上是针对mybatisplus
的一些简单改造,希望能为你提供一点点帮助~
作者:京东科技 郭艳红
来源:京东云开发者社区 转载请注明来源