MyBatis和数据库交互的过程
MyBatis与数据库交互一次的过程是:先创建SqlSessionFactoryBuilder的实例,然后通过这个Builder的一个build方法创建SqlSessionFactory工厂,再通过这个工厂创建一个SqlSession对象.然后通过这个sqlSession对象和数据库进行交互的.
一级缓存
每当一个新 sqlSession 被创建,MyBatis 就会创建一个与之相关联的本地缓存。任何在 sqlSession 执行过的查询结果都会被保存在本地缓存中,所以,当再次执行参数相同的相同查询时,就不需要实际查询数据库了。本地缓存将会在做出修改、事务提交或回滚,以及关闭 session 时清空。一级缓存是默认开启的 举个例子说明: 比如查询id为2的用户.通过sqlSession对象带着这个id去查询用户;这时候会和数据库交互一次(即执行一次sql语句).紧接着如果在通过这个sqlSession对象再拿着这个id去查询这个用户,MyBatis就不会和数据库进行交互了,因为第一次查询出这个id的用户之后,还用户被保存到sqlSession的缓存区中了(这个缓存是一个map,这就是一级缓存);第二次查询会先查询缓存中是否存在,存在则取出使用.所以说MyBatis的一级缓存是基于SqlSession层的;
一级缓存失效的情况
- sqlSession不是同一个
- sqlSession相同,但是查询条件不同
- sqlSession相同,两次查询之间执行了增删改操作
- sqlSession相同,手动清除一级缓存(调用clearCache方法)
- 执行commit,close等操作也会清空缓存
二级缓存
因为一级缓存的作用域仅限于SqlSession层面,多个SqlSession间的缓存不共享.二级缓存就是为了让同一个namespace的多个SqlSession共享同一块缓存而引入的.每一个namespace(编写sql语句所在的配置文件中mapper标签的一个属性)有一块自己独立的二级缓存区.所以MyBatis的二级缓存是namespace级别的缓存,只有当一级缓存的会话关闭时才会将一级缓存的数据上传到二及缓存中.即如果一级缓存没有关闭的情况下,其他SqlSession同样条件查询还是会执行一次sql文与数据库进行交互
二级缓存还有一个前提是所有的SqlSession是从同一个SqlSessionFactory创建出来的;
二级缓存用到的实体类得实现序列化接口Serializable
二级缓存使用步骤
-
在MyBatis的核心配置文件中配置: <settings>
<setting name="cacheEnabled" value="true"/>
</settings>
-
在namespace所在的xml文件中配置: <cache></cache>(如果想和其他namespace使用同一个二级缓存,可以使用<cache-ref namespace=""/>)
在这个标签中可以设置的属性:
1. eviction: 缓存回收策略,有这几种回收策略;默认值是LRU
LRU - 最近最少回收,移除最长时间不被使用的对象
FIFO - 先进先出,按照缓存进入的顺序来移除它们
SOFT - 软引用,移除基于垃圾回收器状态和软引用规则的对象
WEAK - 弱引用,更积极的移除基于垃圾收集器和弱引用规则的对象
2. flushInterval: 缓存刷新间隔(缓存多长时间清空一次,默认不清空,设置一个毫秒值)
3. readOnly: 是否是只读级别的缓存;默认是false(即两次查询出的都对象地址不同,修改属性时不会互相影响)
true: 直接返回二级缓存中数据的地址
false: 将二级缓存中数据克隆一份给返回去.
4. size: 二级缓存的最大容量
二级缓存失效的情况
- 第一次的sqlSession未提交
- 同一个namespace下的SqlSession进行了增删改操作(因为增删改的sql标签有一个属性是默认开启刷新一级和二级缓存的:flushCache=“true”)
- 在增删改的sql标签中关掉了二级缓存.使用useCache="false"属性
新的会话查询缓存的顺序
新的会话只会在自己所在的namespace中去查询,先去二级缓存查,查不到再去一级缓存,在查不到就去执行sql语句去数据库查
|