mybatis面试题

一、mapper 实现原理

在这里插入图片描述
MapperRegistry 类 getMapper方法

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
		//    获取Mapper接口(type)对应的MapperProxyFactory
        MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
        if (mapperProxyFactory == null) {
            throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
        } else {
            try {
                return mapperProxyFactory.newInstance(sqlSession);
            } catch (Exception var5) {
                throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
            }
        }
    }

public T newInstance(SqlSession sqlSession) {
// 根据sqlsession 获取MapperProxy
        MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
        return this.newInstance(mapperProxy);
}

protected T newInstance(MapperProxy<T> mapperProxy) {
// 创建代理对象
        return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}

最终执行mapper 里面方法 实际是执行MapperProxy invoke()方法

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            if (Object.class.equals(method.getDeclaringClass())) {
                return method.invoke(this, args);
            }

            if (this.isDefaultMethod(method)) {
                return this.invokeDefaultMethod(proxy, method, args);
            }
        } catch (Throwable var5) {
            throw ExceptionUtil.unwrapThrowable(var5);
        }

        MapperMethod mapperMethod = this.cachedMapperMethod(method);
        return mapperMethod.execute(this.sqlSession, args);
    }

// 这里面截取一部分 MapperMethod方法
// 通过MappedStatement 获取要执行哪个方法 因为 insert|update|delete|select每一个标签都对应一个MappedStatement
public class MapperMethod {
    private final MapperMethod.SqlCommand command;
    private final MapperMethod.MethodSignature method;

    public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
        this.command = new MapperMethod.SqlCommand(config, mapperInterface, method);
        this.method = new MapperMethod.MethodSignature(config, mapperInterface, method);
    }

    public Object execute(SqlSession sqlSession, Object[] args) {
        Object param;
        Object result;
        // 判断要执行 哪一种操作
        switch(this.command.getType()) {
        case INSERT:
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
            break;
        case UPDATE:
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
            break;
        case DELETE:
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
            break;
        case SELECT:
            if (this.method.returnsVoid() && this.method.hasResultHandler()) {
                this.executeWithResultHandler(sqlSession, args);
                result = null;
            } else if (this.method.returnsMany()) {
                result = this.executeForMany(sqlSession, args);
            } else if (this.method.returnsMap()) {
                result = this.executeForMap(sqlSession, args);
            } else if (this.method.returnsCursor()) {
                result = this.executeForCursor(sqlSession, args);
            } else {
                param = this.method.convertArgsToSqlCommandParam(args);
                result = sqlSession.selectOne(this.command.getName(), param);
            }
            break;
        case FLUSH:
            result = sqlSession.flushStatements();
            break;
        default:
            throw new BindingException("Unknown execution method for: " + this.command.getName());
        }

        if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
            throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
        } else {
            return result;
        }
    }
}

二、mybatis 有几级缓存,缓存原理

  • 一级缓存sqlsession级别得缓存,默认开启得,不可关闭,但是可以在DML操作时 自动清除缓存,也可手动清除缓存,因为一级缓存时会话级别的所以 只有使用同一个sqlsession才会用到一级缓存,例如 spring的事务控制实在serivce层 ,当我们重复调用同一个service中得方法,是不会使用一级缓存得 因为当第二次调用的时候 sqlsession已经关闭了
  • 二级缓存 mapper级别得 所有同一个namespace 下的sqlsession共享缓存,默认关闭,可手动开启
    一级缓存和耳机缓存都会在DML操作时进行清空操作,防止脏数据

三、mybatis 除了insert 、select、update 、delete等等还有那些标签

动态标签 等等

四、resultMap 和resultType 区别

resultype 返回的对象类型 所有返回字段必须与相应的pojo 一一对应
resultmap 如果返回属性与对象属性不一致可以通过一个resultmap 转换 与之进行映射

五、#{} 和 ${} 区别

#{} 时占位符 ${} 是替换符号
比如在传值的时候 #{} 会被替换成 ? 之后调用PreparedStatement 进行赋值之后在外面加上单引号
但是 ${} 是传入什么值就拼接什么值
name = “zhangsan”
#{name} --> where name = ‘zhangsan’
${name} —> where name = shangsan

比如我登录时候不知道密码 但是使用的是 ${ } 进行占位的 则输入时候就可以进行sql注入
password = "111 "
where password = ‘111’ 这应该是正常情况下的sql
这时候如果使用的 ${} 我就可以进行sql 拼接
参数 password= “111 or 1=1”
where password = 111 or 1=1

六、mybatis 有哪些执行器

SimpleExecutor、ReuseExecutor,BatchExecutor

  • SimpleExecutor 每一次执行sql 都会生成一个新得java.sql.statement
  • ReuseExecutor 在 SimpleExecutor 基础上维护了一个map 缓存相同的sql 不会生成新的SimpleStatement,复用之前的SimpleStatement
  • BatchExecutor 批量处理器 维护了一组 用于DML的SimpleStatement
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值