#{}
和${}
区别
#{}
是 SQL中的参数占位符、执行时会按顺序替换成传进来的参数。执行时,先编译后取值,取值时会自动为参数添加引号,因此可以防止sql注入。
${}
是 Properties 文件中的变量占位符,会替换成定义好的文本变量。执行时,先取值后编译,取值时直接将字符拼接在sql语句中。
Dao接口原理
底层使用映射和动态代理实现。执行时会为 Dao 创建代理类,代理类通过接口的全限名+方法名作为 key,拿到作为 value 的MappedStatement
对象,并执行其代表的 SQL 语句。拿到查询结果后,通过反射创建对象,根据<resultMap>
标签的对象属性和sql列的映射关系,使用反射给对象的属性逐一赋值。
MappedStatement
是 Mybatis 框架的核心类之一,它存储了一个 SQL 对应的所有信息。Mybatis 通过解析 XML和 Mapper 接口上的注解,生成 sql 对应的MappedStatement
实例。- 全限名在 XML 的
namespace
属性中,方法名在id
属性中,例:
Dao 中
package com.xxx.xxx.dao;
@Mapper
public interface UserMapper {
User selectByName(String username);
}
Mapper 中
<mapper namespace="com.xxx.xxx.dao.UserMapper">
<select id="selectByName">
...sql...
</>
</mapper>
分页
- 使用
RowBounds
对象。使用RowBounds
对象时,是从数据库中取出所有符合条件的信息到内存中,在内存中进行分页。因此,当数据量大的时候,不推荐使用。 - 直接在 SQL 中使用
limit...offset...
等条件进行物理分页。 - 自定义 MyBatis 自带的分页插件。
动态sql
使用MyBatis提供的9种标签
<if></if>
<where></where>
<choose></choose>
<foreach></foreach>
<bind/>
执行器
MyBatis 有三种基本的 Executor 执行器:
SimpleExecutor
: 每执行一次 update 或 select,就开启一个Statement
对象,用完立刻关闭 Statement 对象。ReuseExecutor
: 执行 update 或 select,以 SQL作为 key 查找Statement
对象,存在就使用,不存在就创建,用完后,不关闭Statement
对象,而是放置于 Map<String, Statement> 内,供下一次使用。简言之,就是重复使用Statement
对象。BatchExecutor
:执行 update(没有 select,JDBC 批处理不支持 select),将所有 SQL都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement
对象,每个Statement
对象都是 addBatch()完毕后,等待逐一执行 executeBatch()批处理。与 JDBC 批处理相同。
缓存
MyBatis自带一级缓存和二级缓存。
- 一级缓存是
Session
级别,默认开启。即在同一个SqlSession
中,对于同一条 SQL 语句,MyBatis 会缓存查询结果,在后续的查询操作中,若执行相同的SQL,MyBatis 会直接返回缓存种的结果。由于一级缓存是基于SqlSession
的,当Session
关闭时,缓存会被清空。 - 二级缓存是
Mapper
级别,是基于SqlSessionFactory
的,它可以缓存多个SqlSession
的查询结果。当多个SqlSession
对同一条 SQL 语句进行查询时,MyBatis会尝试从二级缓存中获取结果,如果找到了数据,会将其放入对应Session
的一级缓存中,并返回结果。
既然 Mybatis 有缓存,为什么要使用 redis?
- MyBatis是本地的,不适用于分布式场景。
- MyBatis没有对数据做持久化,当系统重启或缓存过期,所有的缓存都会丢失。