012_Mybatis小记

2020-10-18   24 次阅读


2.1 #{}和${}的区别

动态SQL

动态 SQL 是 mybatis 的强大特性之一,也是它优于其他 ORM 框架的一个重要原因。mybatis 在对 sql 语句进行预编译之前会对 sql 进行动态解析,解析为一个 BoundSql 对象,也是在此处对动态 SQL 进行处理的。在动态 SQL 解析阶段, #{ } 和 ${ } 会有不同的表现

  1. #{} 在动态解析的时候, 会解析成一个参数标记符,select * from user where name = ?;
  2. ${}在动态解析的时候,会将我们传入的参数当做String字符串填充到我们的语句中,select * from user where name = "dato"; 预编译之前的 SQL 语句已经不包含变量了,完全已经是常量数据了。
区别
  1. #方式能够很大程度防止sql注入。
  2. $方式无法防止Sql注入。
  3. $方式一般用于传入数据库对象,例如传入表名.
  4. 一般能用#的就别用$.

2.2 Dao接口与XML

  1. Dao接口就是Mapper接口,接口的全限名就是XML文件中的namespace的值,接口的方法名就是映射文件中MappedStatement的id值,接口方法内的参数就是传递给sql的参数。
  2. Mapper接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为key值,可在XML文件唯一定位一个MappedStatement。Dao接口里的方法是不能重载的,因为是全限名+方法名的保存和寻找策略。
  3. Dao接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Dao接口生成代理proxy对象,代理对象proxy会拦截接口方法,转而执行MappedStatement所代表的sql,然后将sql执行结果返回。

2.3 分页功能

  1. Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页而非物理分页,可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。
  2. 分页插件的基本原理是使用Mybatis提供的插件接口实现自定义插件,在插件的拦截方法内拦截待执行的sql并重写sql,根据dialect方言添加对应的物理分页语句和物理分页参数。

2.4 插件运行原理

  1. Mybatis仅可以编写针对ParameterHandler、ResultSetHandler、StatementHandler、Executor这4种接口的插件,Mybatis使用JDK的动态代理为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这4种接口对象的方法时就会进入拦截方法,具体就是InvocationHandler的invoke()方法,当然,只会拦截那些你指定需要拦截的方法。

  2. 实现Mybatis的Interceptor接口并复写intercept()方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法,最后在配置文件中配置编写的插件。

2.5 mybaits动态SQL

  1. Mybatis动态sql可以让我们在Xml映射文件内,以标签的形式编写动态sql,完成逻辑判断和动态拼接sql的功能。
  2. Mybatis提供了9种动态sql标签trim|where|set|foreach|if|choose|when|otherwise|bind。
  3. 其执行原理为,使用OGNL从sql参数对象中计算表达式的值,根据表达式的值动态拼接sql,以此来完成动态sql的功能。

2.6 mybatis如何封装sql结果

  1. 使用标签,逐一定义列名和对象属性名之间的映射关系。
  2. 使用sql列的别名功能,将列别名书写为对象属性名
  3. Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。

2.7 mybatis懒加载

  1. Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。
  2. 使用CGLIB创建目标对象的代理对象,当调用目标方法时进入拦截器方法,拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。

Q.E.D.

知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议