11、说说Mybatis的缓存机制
- mybatis整体:
- 一级缓存localCache
- 在应用运行过程中,我们有可能在一次数据库会话中,执行多次查询条件完全相同的 SQL,
MyBatis 提供了一级缓存的方案优化这部分场景,如果是相同的 SQL 语句,会优先命中一级缓存,避免直接对数据库进行查询,提高性能。 - 每个 SqlSession 中持有了 Executor,每个 Executor 中有一个 LocalCache。当用户发起查询时,MyBatis 根据当前执行的语句生成 MappedStatement,在 Local Cache 进行查询,如果缓存命中的话,直接返回结果给用户,如果缓存没有命中的话,查询数据库,结果写入 Local Cache,最后返回结果给用户。具体实现类的类关系图如下图所示:
-
- MyBatis 一级缓存的生命周期和 SqlSession 一致。
-
- MyBatis 一级缓存内部设计简单,只是一个没有容量限定的 HashMap,在缓存的功能性上有所欠缺。
-
- MyBatis 的一级缓存最大范围是 SqlSession 内部,有多个 SqlSession 或者分布式的环境下,数据库写操作会引起脏数据,建议设定缓存级别为 Statement。
- MyBatis 的一级缓存最大范围是 SqlSession 内部,有多个 SqlSession 或者分布式的环境下,数据库写操作会引起脏数据,建议设定缓存级别为 Statement。
-
- 在应用运行过程中,我们有可能在一次数据库会话中,执行多次查询条件完全相同的 SQL,
- 二级缓存
- 在上文中提到的一级缓存中,其最大的共享范围就是一个 SqlSession 内部,如果多个 SqlSession之间需要共享缓存,则需要使用到二级缓存。开启二级缓存后,会使用 CachingExecutor 装饰Executor,进入一级缓存的查询流程前,先在 CachingExecutor 进行二级缓存的查询,具体的工作流程如下所示。
二级缓存开启后,同一个 namespace 下的所有操作语句,都影响着同一个 Cache,即二级缓存被
多个 SqlSession 共享,是一个全局的变量。
- 在上文中提到的一级缓存中,其最大的共享范围就是一个 SqlSession 内部,如果多个 SqlSession之间需要共享缓存,则需要使用到二级缓存。开启二级缓存后,会使用 CachingExecutor 装饰Executor,进入一级缓存的查询流程前,先在 CachingExecutor 进行二级缓存的查询,具体的工作流程如下所示。
- 当开启缓存后,数据的查询执行的流程为:
- 二级缓存 -> 一级缓存 -> 数据库
-
- MyBatis 的二级缓存相对于一级缓存来说,实现了 SqlSession 之间缓存数据的共享,同时粒度更加细,能够到 namespace 级别,通过 Cache 接口实现类不同的组合,对 Cache 的可控性也更强。
-
- MyBatis 在多表查询时,极大可能会出现脏数据,有设计上的缺陷,安全使用二级缓存的条件比较苛刻。
-
- 在分布式环境下,由于默认的 MyBatis Cache 实现都是基于本地的,分布式环境下必然会出现读取到脏数据,需要使用集中式缓存将 MyBatis 的 Cache 接口实现,有一定的开发成本,直接使用 Redis、Memcached 等分布式缓存可能成本更低,安全性也更高。
-
- 二级缓存 -> 一级缓存 -> 数据库
12、JDBC 编程有哪些步骤?
- 装载相应的数据库的 JDBC 驱动并进行初始化:
Class.forName("com.mysql.jdbc.Driver");
- 建立 JDBC 和数据库之间的 Connection 连接:
Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?
characterEncoding=UTF-8", "root", "123456");
- 创建 Statement 或者 PreparedStatement 接口,执行 SQL 语句。
- 处理和显示结果。
- 释放资源。
13、MyBatis 中见过什么设计模式?
14、MyBatis 中比如 UserMapper.java 是接口,为什么没有实现类还能调用?
使用JDK动态代理+MapperProxy。本质上调用的是MapperProxy的invoke方法。
15、如何获取自动生成的(主)键值?
- insert 方法总是返回一个 int 值 ,这个值代表的是插入的行数。
- 如果采用自增长策略,自动生成的键值在 insert 方法执行完后可以被设置到传入的参数对象中。
示例:
<insert id=”insertname” usegeneratedkeys=”true” keyproperty=”
id”>
insert into names (name) values (#{name})
</insert>
name name =newname();
name.setname(“fred”);
int rows = mapper.insertname(name);
// 完成后,id已经被设置到对象中
system.out.println(“rows inserted = ” + rows);
system.out.println(“generated key value = ” + name.getid());
16、在mapper中如何传递多个参数?
- 第一种:DAO层的函数
publicUserselectUser(String name,String area);
对应的xml,#{0}代表接收的是dao层中的第一个参数,#{1}代表dao层中第二参数,更多参数一致往后加即可。
<select id="selectUser"resultMap="BaseResultMap">
select * fromuser_user_t where user_name=#{0}
and user_area=#{1}
</select>
- 第二种:使用@param注解:
publicinterfaceusermapper{
userselectuser(@param(“username”)string
username,@param(“hashedpassword”)string hashedpassword);
}
然后,就可以在xml像下面这样使用(推荐封装为一个map,作为单个参数传递给mapper):
<select id=”selectuser” resulttype=”user”>
select id,username,hashedpassword
from some_table
where username=#{username}
and hashedpassword=#{hashedpassword}
</select>
- 第三种:多个参数封装成map
try {
//映射文件的命名空间.SQL片段的ID,就可以调用对应的映射文件中的
SQL
//由于我们的参数超过了两个,而方法中只有一个Object参数收集,因此我们使用Map集合来装载我们的参数
Map <String, Object > map = new HashMap();
map.put("start", start);
map.put("end", end);
return sqlSession.selectList("StudentID.pagination", map);
} catch (Exception e) {
e.printStackTrace();
sqlSession.rollback();
throw e;
} finally {
MybatisUtil.closeSqlSession();
}
17、Mybatis 动态sql有什么用?执行原理?有哪些动态sql?
-
Mybatis 动态 sql 可以在 Xml 映射文件内,以标签的形式编写动态 sql,执行原理
是根据表达式的值 完成逻辑判断并动态拼接sql的功能。 -
Mybatis 提供了 9种动态 sql标签:trim | where | set | foreach | if | choose | when | otherwise | bind。
18、Xml映射文件中,除了常见的select|insert|updae|delete标签之外,还有哪些标签?
<resultMap>、<parameterMap>、<sql>、<include>、
<selectKey>,加上动态 sql 的 9 个标签,其中<sql>为 sql 片段标签,
通过<include>标签引入 sql 片段,<selectKey>为不支持自增的主键生成策略标签。
19、Mybatis 的 Xml 映射文件中,不同的 Xml映射文件,id是否可以重复?
- 不同的Xml映射文件,如果配置了namespace,那么 id可以重复;如果没有配置 namespace,那么 id 不能重复;
- 原因就是namespace+id 是作为 Map<String, MapperStatement>的 key使用的。
- 如果没有namespace,就剩下 id,那么,id重复会导致数据互相覆盖。
- 有了namespace,自然 id 就可以重复,namespace 不同,namespace+id 自然也就不同。
20、为什么说Mybatis是半自动ORM映射工具?它与全自动的区别在哪里?
- Hibernate 属于全自动 ORM 映射工具,使用 Hibernate 查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。而Mybatis在查询关联对象或关联集合对象时,需要手动编写sql来完成,所以,称之为半自动 ORM映射工具。