在MyBatis中, #{}和${}的区别是什么?
- #{}是预编译处理, ${}是字符串替换
- MyBatis 在处理 #{} 时,会将 SQL 中的 #{} 替换为 ? 号,调⽤ PreparedStatement 的 set ⽅法来赋值;
- MyBatis在处理${}时, 就是把它替换成变量的值;
- #{}能够有效防止SQL注入, 提高系统安全性
阐述Mapper接口原理
一般的, 我们在使用MyBatis操作数据时, 只需要定义一个mapper xml, 和一个与之对应的Mapper接口即可, 但是并不需要提供 Mapper 接口的实现类, 可以这么做的原因是 MyBatis 基于JDK的动态代理技术为我们的 Mapper 接口生成了动态代理类, 操作的时候调用的也是该动态的动态代理类对象的方法。
在解析全局配置文件过程中, 有一个很重要的步骤就是解析 mapper 标签对应的 mapper xml或者是Mapper接口注解类, 在解析的过程中会使用接口信息创建 MapperProxyFactory类, 这是一个用于创建MapperProxy的工厂类, 而MapperProxy 是java.lang.reflect.InvocationHandler的实现类(用于使用动态代理创建Mapper接口实现类对象的), 然后当我们调用 sqlSession.getMapper()方法时, 内部就会调用MapperProxyFactory的 newInstance 方法获取对应的 Mapper 接口实现类对象, 最后当我们调用 Mapper 接口实现类对象的任何方法时, 就会去调用到这个MapperProxy类型对象的 invoke 方法, 其里面本质还是以前命名空间的方式。
MyBatis是否支持延迟加载? 如果支持, 它的实现原理是什么?
MyBatis仅支持association关联对象和collection关联集合对象的延迟加载, association指的就是一对一, collection指的就是一对多查询。在MyBatis配置文件中, 可以配置是否启用延迟加载LazyLoadingEnabled = true|false。
它的原理是, 使用Javasissit(默认)创建目标对象的代理对象, 当调用目标方法时, 进入拦截器方法, 比如调用a.getB().getName(), 拦截器invoke()方法发现a.getB()是null值, 那么就会单独发送事先保存好的查询关联B对象的SQL, 把B查询上来, 然后调用a.setB(b), 于是a的对象b属性就有值了, 接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。