本文最后更新于:2020年12月30日 凌晨
场景
为 mybatis-plus
自定义了一个全局操作,然后就一直返回 null
。。。
在自定义 sql 注入器类的时候,突然发现 existsById()
一直都在抛空指针异常,就去看了一下结果发现一直返回 null
。
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
| package com.rxliuli.example.mybatisplussqlinjector.config;
import com.baomidou.mybatisplus.entity.TableInfo; import com.baomidou.mybatisplus.mapper.AutoSqlInjector; import org.apache.ibatis.builder.MapperBuilderAssistant; import org.apache.ibatis.mapping.SqlSource; import org.apache.ibatis.session.Configuration;
public class CustomSqlInjector extends AutoSqlInjector {
private static final String SQL_EXISTS_BY_ID = "select exists(select 0 from %s where id = #{id});";
@Override public void inject(Configuration configuration, MapperBuilderAssistant builderAssistant, Class<?> mapperClass, Class<?> modelClass, TableInfo table) { existsById(mapperClass, modelClass, table); }
public void existsById(Class<?> mapperClass, Class<?> modelClass, TableInfo table) { final String sql = String.format(SQL_EXISTS_BY_ID, table.getTableName()); final SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass); this.addSelectMappedStatement(mapperClass, "existsById", sqlSource, modelClass, table); } }
|
自定义的 BaseDao
基类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package com.rxliuli.example.mybatisplussqlinjector.common.dao;
import com.baomidou.mybatisplus.mapper.BaseMapper; import org.apache.ibatis.annotations.Param;
import java.io.Serializable;
public interface BaseDao<T extends Serializable> extends BaseMapper<T> {
Boolean existsById(@Param("id") Long id); }
|
测试代码
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
| package com.rxliuli.example.mybatisplussqlinjector.dao;
import com.rxliuli.example.mybatisplussqlinjector.entity.User; import common.test.BaseDaoAndServiceTest; import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class UserDaoTest extends BaseDaoAndServiceTest<UserDao> { @Test public void existsById() { final Boolean res = base.existsById(1L); log.debug("res: {}", res); assertThat(res) .isTrue(); }
@Test public void selectById() { final User user = base.selectById(1L); log.debug("user: {}", user); assertThat(user) .isNotNull(); } }
|
结果
然而,当我把全局注入的 sql 操作放到 xml 文件时
Dao 和对应的 xml 文件
1 2 3 4 5 6 7 8 9 10 11 12
| package com.rxliuli.example.mybatisplussqlinjector.dao;
import com.rxliuli.example.mybatisplussqlinjector.common.dao.BaseDao; import com.rxliuli.example.mybatisplussqlinjector.entity.User; import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository;
@Repository public interface UserDao extends BaseDao<User> { @Override Boolean existsById(@Param("id") Long id); }
|
1 2 3 4 5 6 7 8 9
| <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.rxliuli.example.mybatisplussqlinjector.dao.UserDao"> <select id="existsById" resultType="java.lang.Boolean"> select exists(select 0 from user where id = #{id}); </select> </mapper>
|
现在,一切又能正常运行了,这其中到底发生了什么呢?
目前该问题已经在 官方 GitHub 上提出了一个 issue
解决
好吧,开发人员说是要在使用 addSelectMappedStatement()
时对返回值进行界定,之前一直查的都是表数据确实没注意到还需要对返回值类型进行界定呢
修改的地方其实只有一处
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
| package com.rxliuli.example.mybatisplussqlinjector.config;
import com.baomidou.mybatisplus.entity.TableInfo; import com.baomidou.mybatisplus.mapper.AutoSqlInjector; import org.apache.ibatis.builder.MapperBuilderAssistant; import org.apache.ibatis.mapping.SqlSource; import org.apache.ibatis.session.Configuration;
public class CustomSqlInjector extends AutoSqlInjector {
private static final String SQL_EXISTS_BY_ID = "select exists(select 0 from %s where id = #{id});";
@Override public void inject(Configuration configuration, MapperBuilderAssistant builderAssistant, Class<?> mapperClass, Class<?> modelClass, TableInfo table) { existsById(mapperClass, modelClass, table); }
public void existsById(Class<?> mapperClass, Class<?> modelClass, TableInfo table) { final String sql = String.format(SQL_EXISTS_BY_ID, table.getTableName()); final SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass); this.addSelectMappedStatement(mapperClass, "existsById", sqlSource, Boolean.class, table); } }
|
代码已经上传到 GitHub
虽然只是个不起眼的小错误,不过这里还是记录一下吧,毕竟坑只要踩过一次就够了 ┐( ̄ヮ ̄)┌