在mybatis-plus内部实现了一系列的操作数据库的SQL语句方法,但是某些特殊情况这些方法不能满足需求时,如何自定义通用方法呢?首先我们研究一下mybatis-plus内部如何实现的?
主要是通过下类定义的
public class DefaultSqlInjector extends AbstractSqlInjector {
public DefaultSqlInjector() {
}
public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
Builder<AbstractMethod> builder = Stream.builder().add(new Insert()).add(new Delete()).add(new DeleteByMap()).add(new Update()).add(new SelectByMap()).add(new SelectCount()).add(new SelectMaps()).add(new SelectMapsPage()).add(new SelectObjs()).add(new SelectList()).add(new SelectPage());
if (tableInfo.havePK()) {
builder.add(new DeleteById()).add(new DeleteBatchByIds()).add(new UpdateById()).add(new SelectById()).add(new SelectBatchByIds());
} else {
this.logger.warn(String.format("%s ,Not found @TableId annotation, Cannot use Mybatis-Plus 'xxById' Method.", tableInfo.getEntityType()));
}
return (List)builder.build().collect(Collectors.toList());
}
}
而这些方法实现是通过继承类来实现AbstractMethod,比如Insert类
最关键的部分通过injectMappedStatement方法生成操作数据的SQL,还有里面最关键的sqlMethod
public class Insert extends AbstractMethod {
public Insert() {
super(SqlMethod.INSERT_ONE.getMethod());
}
public Insert(String name) {
super(name);
}
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE;
SqlMethod sqlMethod = SqlMethod.INSERT_ONE;
String columnScript = SqlScriptUtils.convertTrim(tableInfo.getAllInsertSqlColumnMaybeIf((String)null), "(", ")", (String)null, ",");
String valuesScript = SqlScriptUtils.convertTrim(tableInfo.getAllInsertSqlPropertyMaybeIf((String)null), "(", ")", (String)null, ",");
String keyProperty = null;
String keyColumn = null;
if (StringUtils.isNotBlank(tableInfo.getKeyProperty())) {
if (tableInfo.getIdType() == IdType.AUTO) {
keyGenerator = Jdbc3KeyGenerator.INSTANCE;
keyProperty = tableInfo.getKeyProperty();
keyColumn = tableInfo.getKeyColumn();
} else if (null != tableInfo.getKeySequence()) {
keyGenerator = TableInfoHelper.genKeyGenerator(this.methodName, tableInfo, this.builderAssistant);
keyProperty = tableInfo.getKeyProperty();
keyColumn = tableInfo.getKeyColumn();
}
}
String sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(), columnScript, valuesScript);
SqlSource sqlSource = this.languageDriver.createSqlSource(this.configuration, sql, modelClass);
return this.addInsertMappedStatement(mapperClass, modelClass, this.getMethod(sqlMethod), sqlSource, (KeyGenerator)keyGenerator, keyProperty, keyColumn);
}
}
另外需要实际可以使用,mybatis-plus是在BaseMapper接口中定义了Insert方法:
public interface BaseMapper<T> extends Mapper<T> {
int insert(T entity);
int deleteById(Serializable id);
int deleteById(T entity);
int deleteByMap(@Param("cm") Map<String, Object> columnMap);
下面我们看一下如何实现自定义method
1.准备CustomMethod类
public class CustomMethod extends AbstractMethod {
private String method="customMethod";
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
String sql="select id,name,age,version from "+tableInfo.getTableName()+" where "+tableInfo.getKeyColumn()+ "=#{" + tableInfo.getKeyProperty() + "}";
SqlSource sqlSource= languageDriver.createSqlSource(configuration,sql,modelClass);
return addSelectMappedStatementForTable(mapperClass,method,sqlSource,tableInfo);
}
}
2.准备SqlInject类
public class CustomSqlInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
List<AbstractMethod> methodList= super.getMethodList(mapperClass, tableInfo);
methodList.add(new CustomMethod());
return methodList;
}
}
3.准备CustomMapper类继承BaseMapper类,在里面添加自定义方法
public interface CustomBaseMapper<T> extends BaseMapper<T> {
T customMethod(Serializable id);
}
4.在Configuration类中生成CustomSqlInjector 的Bean
@Configuration
public class MybatisPlusConfig {
@Bean
public CustomSqlInjector customSqlInjector(){
return new CustomSqlInjector();
}
5.让UserMapper继承CustomMapper类
public interface UserMapper extends CustomBaseMapper<User> {
@Select("select * from user ${ew.customSqlSegment}")
List<User> selectAllUser(@Param(Constants.WRAPPER)Wrapper<User> wrapper);
List<User> selectUsers(@Param(Constants.WRAPPER)Wrapper<User> wrapper);
IPage<User> selectUserPage(Page<User> page,@Param(Constants.WRAPPER)Wrapper<User> wrapper);
}
6.准备测试用例
@Test
public void testCustomMethod(){
User user= userMapper.customMethod(413l);
System.out.println(user);
}
7.运行日志
2022-10-11 18:48:33.049 DEBUG 26000 --- [ main] c.m.s.mapper.UserMapper.customMethod : ==> Preparing: SELECT id, name, age, version FROM user WHERE id = ? AND user.FAB = 'FAB1'
2022-10-11 18:48:33.078 DEBUG 26000 --- [ main] c.m.s.mapper.UserMapper.customMethod : ==> Parameters: 413(Long)
Consume Time:10 ms 2022-10-11 18:48:33
Execute SQL:SELECT id, name, age, version FROM user WHERE id = 413 AND user.FAB = 'FAB1'
2022-10-11 18:48:33.104 DEBUG 26000 --- [ main] c.m.s.mapper.UserMapper.customMethod : <== Total: 1
另外mybatis-plus还提供一些选装方法,具体如下,在使用时需要按照上面的方法进行。
public class AlwaysUpdateSomeColumnById extends AbstractMethod
public class InsertBatchSomeColumn extends AbstractMethod
public class LogicDeleteBatchByIds extends DeleteBatchByIds
public class LogicDeleteByIdWithFill extends AbstractMethod
public class Upsert extends AbstractMethod