一、背景
很多朋友应该有这个疑问,使用Mybatis的时候,需要数据操作的场景,是需要自己在xml里面写sql语句的(或者用@Select之类的注解sql写在里面),只要你需要操作数据库,一定要自己写对应的sql(自己封装框架那种除外)。但是升级了mybatisplus以后,常用的单表增删改查就不需要自己写sql了。 今天跟大家简单聊一下实现(要完全理解细节依赖对spring框架bean处理的掌握程度,大致理解只要稍微有点基础就可以)
二、代码分析
基础方式在IService接口内,有save,update,delete相关方法,今天以updateById方法为例
package com.baomidou.mybatisplus.extension.service;
public interface IService<T> {
/**
* 根据 ID 选择修改
*
* @param entity 实体对象
*/
boolean updateById(T entity);
}
实现类SerViceImpl,调用baseMapper的updateById方法
@Override
public boolean updateById(T entity) {
return retBool(baseMapper.updateById(entity));
}
但是BaseMapper是个接口,没有实现类,咋办呢? 这里教大家一个方式,适用于大部分场景,直接搜全文搜这个方法。可以看到,第二行有个update的sql很像我们需要的,点进去再找使用这个的地方
第一个比较像
UpdateById这个类的setSql这行看着最像
package com.baomidou.mybatisplus.core.injector.methods;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
public class UpdateById extends AbstractMethod {
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
boolean logicDelete = tableInfo.isLogicDelete();
SqlMethod sqlMethod = SqlMethod.UPDATE_BY_ID;
final String additional = optlockVersion() + tableInfo.getLogicDeleteSql(true, false);
String sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(),
//这行 sqlSet(logicDelete, false, tableInfo, false, ENTITY, ENTITY_DOT),
tableInfo.getKeyColumn(), ENTITY_DOT + tableInfo.getKeyProperty(), additional);
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
return addUpdateMappedStatement(mapperClass, modelClass, sqlMethod.getMethod(), sqlSource);
}
}
通过实体表信息获取sql脚本片段,就是我们经常写的<if test param!=null />之类的xml里面的代码
protected String sqlSet(boolean logic, boolean ew, TableInfo table, boolean judgeAliasNull, String alias, String prefix) {
String sqlScript = table.getAllSqlSet(logic, prefix);
if (judgeAliasNull) {
sqlScript = SqlScriptUtils.convertIf(sqlScript, String.format("%s != null", alias), true);
}
if (ew) {
sqlScript += NEWLINE;
sqlScript += SqlScriptUtils.convertIf(SqlScriptUtils.unSafeParam(U_WRAPPER_SQL_SET),
String.format("%s != null and %s != null", WRAPPER, U_WRAPPER_SQL_SET), false);
}
sqlScript = SqlScriptUtils.convertSet(sqlScript);
return sqlScript;
}
中间过程省略,有点长,最后走到这里,if test,里面的条件是xxx!=null,默认策略的情况下
public static String convertIf(final String sqlScript, final String ifTest, boolean newLine) {
String newSqlScript = sqlScript;
if (newLine) {
newSqlScript = NEWLINE + newSqlScript + NEWLINE;
}
return String.format("<if test="%s">%s</if>", ifTest, newSqlScript);
}
调用链在下图箭头里了
效果类似于使用@Update注解方式更新,其实跟写xml是一个效果,只是这里plus帮我们自动生产处理了,不需要手动写,问题解决
@Update("<script>\nUPDATE table <set> <if test a!=null>a=#{a}</if>\n<if test b!=null>b=#{b}</if>\n</set> WHERE id=#{id}\n</script>")
int updateById(T entity);
三、结论
- MybatisPlus自带的方法不需要写sql语句即能操作数据库是因为框架自动处理了,模拟了我们在xml里写sql的方式
- updateById方法默认逻辑是用实体id更新,实体字段不为null即更新,该方法要慎用,因为更新字段过多,很多时候会导致覆盖更新(把别人的数据覆盖了,本来更新的原则就是需要更新几个字段更新几个,updateById违背了该原则,放大了风险)
- 本文只列举了部分代码,关于这些方法怎么跟spring关联上这块未展开说明,有兴趣的同学可以自己尝试看看,需要对spring管理和mybatis比较熟悉,否则看起来理解吃力。