mybatis-plus updateById源码

1.版本 : mybatis-plus-core 3.5.1

2.入口:MybatisPlusAutoConfiguration类sqlSessionFactory中的factory.getObject()

3.注入AbstractSqlInjector类中的inspectInject方法中

@Override
    public void inspectInject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass) {
        Class<?> modelClass = ReflectionKit.getSuperClassGenericType(mapperClass, Mapper.class, 0);
        if (modelClass != null) {
            String className = mapperClass.toString();
            Set<String> mapperRegistryCache = GlobalConfigUtils.getMapperRegistryCache(builderAssistant.getConfiguration());
            if (!mapperRegistryCache.contains(className)) {
                TableInfo tableInfo = TableInfoHelper.initTableInfo(builderAssistant, modelClass);
                List<AbstractMethod> methodList = this.getMethodList(mapperClass, tableInfo);
                if (CollectionUtils.isNotEmpty(methodList)) {
                    // 循环注入自定义方法
                    methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass, tableInfo));
                } else {
                    logger.debug(mapperClass.toString() + ", No effective injection method was found.");
                }
                mapperRegistryCache.add(className);
            }
        }
    }

主要是下面两段逻辑:

(1).List<AbstractMethod> methodList = this.getMethodList(mapperClass, tableInfo); 这里的DefaultSqlInjector增加所有的默认方法

@Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
        Stream.Builder<AbstractMethod> builder = Stream.<AbstractMethod>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 {
            logger.warn(String.format("%s ,Not found @TableId annotation, Cannot use Mybatis-Plus 'xxById' Method.",
                tableInfo.getEntityType()));
        }
        return builder.build().collect(toList());
    }

(2).methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass, tableInfo));这里实现默认方法的sql(inject中的injectMappedStatement方法)

public void inject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
    this.configuration = builderAssistant.getConfiguration();
    this.builderAssistant = builderAssistant;
    this.languageDriver = configuration.getDefaultScriptingLanguageInstance();
    /* 注入自定义方法 */
    injectMappedStatement(mapperClass, modelClass, tableInfo);
}

4.UpdateById类实现AbstractMethod接口

public class UpdateById extends AbstractMethod {

    public UpdateById() {
        super(SqlMethod.UPDATE_BY_ID.getMethod());
    }

    /**
     * @since 3.5.0
     * @param name 方法名
     */
    public UpdateById(String name) {
        super(name);
    }

    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        SqlMethod sqlMethod = SqlMethod.UPDATE_BY_ID;
        final String additional = optlockVersion(tableInfo) + tableInfo.getLogicDeleteSql(true, true);
        String sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(),
            sqlSet(tableInfo.isWithLogicDelete(), false, tableInfo, false, ENTITY, ENTITY_DOT),
            tableInfo.getKeyColumn(), ENTITY_DOT + tableInfo.getKeyProperty(), additional);
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
        return addUpdateMappedStatement(mapperClass, modelClass, getMethod(sqlMethod), sqlSource);
    }
}

injectMappedStatement中生成全字段SQL脚本(

<script>

UPDATE xxxxx <set>

<if test="et['changeType'] != null">change_type=#{et.changeType},</if>

<if test="et['creator'] != null">creator=#{et.creator},</if>

<if test="et['createTime'] != null">create_time=#{et.createTime},</if>

update_time=now(),

</set> WHERE id=#{et.id} AND is_delete=0

</script>)

会被封装为 MyBatis 的 MappedStatement,并注册到 MyBatis 的 Configuration 中,

然后通过mapper代理调用

<think>好的,我现在需要回答用户的问题:“这就是mybatis-plus源码。要调用 this.getById((Serializable)idVal) 是不是必须注入basemapper”。用户之前询问了一段MyBatis-Plus的saveOrUpdate方法源码,现在进一步确认是否需要注入BaseMapper来调用getById方法。 首先,我要回顾一下之前的对话,确保我理解上下文。用户提供的代码是MyBatis-Plus中的一个通用方法,用于根据主键是否存在来决定执行插入或更新。用户现在关注的是代码中的this.getById方法是否需要依赖BaseMapper的注入。 接下来,我需要分析这段代码的结构。在MyBatis-Plus中,通常服务层类(如ServiceImpl)会继承BaseMapper,或者更准确地说,服务实现类会持有Mapper的实例。例如,ServiceImpl类会有一个泛型参数指定Mapper类型,并通过依赖注入来获取该Mapper的实例。 在用户提供的代码中,方法saveOrUpdate是在某个服务类中定义的,因为里面调用了this.getById。这里的this很可能指的是一个继承了MyBatis-Plus的ServiceImpl类的服务实现类。ServiceImpl通常会注入对应的Mapper,这样可以直接调用Mapper的方法,比如getById。 因此,用户的问题核心在于是否必须注入BaseMapper才能调用getById。根据MyBatis-Plus的设计,服务实现类(如ServiceImpl)内部确实需要依赖Mapper来执行数据库操作。如果当前类(即包含saveOrUpdate方法的类)没有通过继承或注入的方式获得Mapper,那么调用getById会失败。所以,正确的做法是确保该类注入了对应的Mapper,通常是通过继承ServiceImpl并指定Mapper类型,或者直接注入Mapper实例。 同时,我需要确认用户可能存在的误解。例如,是否可能在不注入Mapper的情况下调用getById?答案是否定的,因为getById是Mapper接口中的方法,必须通过Mapper实例来调用。因此,服务类必须能够访问到该Mapper实例,通常通过依赖注入实现。 另外,我需要考虑用户可能的实际使用场景。用户可能在编写自己的服务类时,尝试复用或参考MyBatis-Plus源码,因此需要明确如何正确配置Mapper的注入,以避免运行时错误。 最后,我要确保回答清晰,分点说明,涵盖必要的情况,比如直接继承ServiceImpl、手动注入Mapper等,并指出常见的错误如忘记注入导致的空指针异常。同时,提醒用户根据具体代码结构进行调整,确保Mapper的正确注入。</think>是的,在 MyBatis-Plus 中调用 `this.getById((Serializable)idVal)` **必须依赖 BaseMapper(或其子类)的支持**,但具体是否需要开发者手动注入,取决于当前类的上下文结构和继承关系。以下是具体分析: --- ### 1. **为什么需要 BaseMapper?** - `getById` 是 MyBatis-Plus **BaseMapper 接口中的方法**,它的功能是通过主键查询单条记录。 - 只有实现了 `BaseMapper<T>` 的类(如自动生成的 `UserMapper` 接口)才具备 `getById` 方法。 - 因此,调用 `getById` 必须通过 **Mapper 实例**(如 `userMapper.getById(...)`)或 **继承 MyBatis-Plus 服务层基类**(如 `ServiceImpl`)。 --- ### 2. **当前代码中的 `this.getById` 如何生效?** 在 MyBatis-Plus 的经典用法中,`saveOrUpdate` 方法通常位于 **Service 实现类**中(如 `UserServiceImpl`)。这类 Service 类会继承 MyBatis-Plus 提供的 `ServiceImpl<M, T>` 基类: ```java public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { // 可以直接调用基类方法:getById、save、updateById 等 } ``` - **关键点**: - `ServiceImpl<M, T>` 的泛型参数 `M` 是继承 `BaseMapper<T>` 的 Mapper 接口(如 `UserMapper`)。 - `ServiceImpl` 内部会自动注入 `M` 类型的 Mapper(即 `baseMapper` 属性),并通过 `this.baseMapper.xxx()` 调用数据库操作。 - `getById` 是 `ServiceImpl` 基类提供的方法,本质是调用 `baseMapper.selectById(id)`。 - **结论**: **如果当前类(包含 `saveOrUpdate` 方法的类)继承了 `ServiceImpl<M, T>`,则无需手动注入 BaseMapper**,因为基类已通过依赖注入完成了 Mapper 的绑定。 --- ### 3. **如果没有继承 `ServiceImpl` 怎么办?** 如果当前类**未继承 `ServiceImpl`**,则需要**手动注入 BaseMapper 实例**,并通过该实例调用 `getById`: ```java @Service public class CustomService { @Autowired private UserMapper userMapper; // 手动注入 Mapper public boolean customSaveOrUpdate(User entity) { // 调用 userMapper.selectById(...) Object idVal = ...; boolean exists = userMapper.selectById((Serializable) idVal) != null; // 其他逻辑... } } ``` --- ### 4. **常见错误场景** - **错误 1**:未继承 `ServiceImpl` 且未注入 Mapper,直接调用 `getById`。 **结果**:抛出空指针异常(`this.baseMapper` 为 `null`)。 - **错误 2**:在非 Service 层类中调用 `getById`。 **解决**:将操作封装到 Service 层,或手动注入 Mapper。 --- ### 5. **总结** - **需要 BaseMapper 支持**:`getById` 最终依赖 `BaseMapper` 的实现(如 `selectById` 方法)。 - **是否需手动注入**: - 若类继承 `ServiceImpl` → **无需手动注入**(基类已自动注入)。 - 若类未继承 `ServiceImpl` → **需手动注入 BaseMapper**(如 `@Autowired private UserMapper userMapper`)。 - **MyBatis-Plus 推荐实践**:通过继承 `ServiceImpl` 编写 Service 层,直接复用基类方法(如 `save`、`getById`、`updateById`),减少重复代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值