文章目錄
- MyBatis快取
- 概述
- 為什么使用快取?
- MyBatis快取
- 一級快取
- 一級快取的生命周期
- 快取失效
- 二級快取
- 作業模式
- 配置二級快取
- 測驗
MyBatis快取
本文中的部分案例代碼來自MyBtais動態sql和特殊符號處理(案例集錦:不定條件查詢+模糊查詢+批量查詢+批量洗掉…)
概述
為什么使用快取?
快取(即cache)的作用是為了減去資料庫的壓力,提高資料庫的性能,快取實作的原理是從資料庫中查詢出來的物件在使用完后不銷毀,而是存盤在記憶體(快取)中,當再次需要獲取該物件時,直接從記憶體中獲取,不再向資料庫執行select陳述句,減少對資料庫的查詢次數,提高了資料庫的性能,快取是使用Map集合存盤資料,
MyBatis快取
MyBatis有一級快取和二級快取之分,
一級快取的作用域是同一個SqlSession,在同一個SqlSession中兩次執行相同的sql陳述句,第一次執行完畢會將資料庫查詢的資料寫到快取(記憶體),第二次會從快取中獲取資料而不進行資料庫查詢,大大提高了查詢效率,當一個SqlSession結束后該SqlSession中的一級快取也就不存在了,MyBtais默認啟動以及快取,
二級快取是多個SqlSession共享的,其作用域是mapper的同一個namespace,不同的sqlSession兩次執行相同namespace下的sql陳述句且向sql中傳遞的引數也相同時,第一次執行完畢會將資料庫中查詢到的資料寫到快取(記憶體),第二次會直接從快取中獲取,從而提高了查詢效率,MyBatis默認不開啟二級快取,需要在MyBtais全域組態檔中進行setting配置開啟二級快取,
一級快取
MyBatis默認開啟一級快取,一級快取只是相對于同一個SqlSession而言,所以在引數個sql完全一致的情況下,我們使用同一個SqlSession物件呼叫一個Mapper方法,往往只執行一次sql,使用SqlSession第一次查詢后,MyBatis會將其放在快取中,之后再查詢時若沒有快取失效或超時,SqlSession都會取出當前快取的資料,不會再發送sql到資料庫,
我們做一個查詢的測驗
/**
* 批量查詢快取
* 快取:將資料臨時存盤在(本地硬碟,記憶體),減少對資料的訪問
*
* 一級快取是SqlSession級別的,MyBatis默認開啟
* 在同一個SqlSession中可以將第一次查詢的資料快取到SqlSession
* 第二次查詢相同資料時,就可以直接從SqlSession獲取
*/
@Test
public void test5() {
try {
Reader reader = Resources.getResourceAsReader("MyBatisConfig.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
SqlSession sqlSession = sessionFactory.openSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
//處理,假設從客戶端傳遞過來要洗掉的多個引數為一個集合
List<Integer> list = new ArrayList<>();
list.add(1);
//查詢
System.out.println("同一個sqlSession中第一次查詢id=1的資料為"+userDao.findUser(list));
System.out.println("---------------");
//第二次查詢
System.out.println("---------------");
System.out.println("同一個sqlSession中第二次查詢id=1的資料為"+userDao.findUser(list));
//提交事務
sqlSession.commit();
sqlSession.close();
} catch (IOException e) {
e.printStackTrace();
}
}

一級快取的生命周期
一級快取的作業程序如圖所示

MyBatis開啟一個資料庫會話時,會創建一個新的SqlSession物件,其中有一個新的Executor物件,Executor物件中持有一個新的PerpetualCache物件,當會話結束時,SqlSession物件及其內部的Executor物件還有PerpetualCache物件會一并釋放掉,
快取失效
1.當SqlSession呼叫close()方法時,SqlSession物件關閉,直接會釋放掉一級快取PerpetualCache物件,一級快取將不可用,
2.如果SqlSession呼叫了clearCache(),會清空PerpetualCache物件中的資料,但是SQlSession物件還可以用,
/**
* 快取失效: close clear 執行新增,修改,洗掉操作會清空一級快取
*/
@Test
public void test5() {
try {
Reader reader = Resources.getResourceAsReader("MyBatisConfig.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
SqlSession sqlSession = sessionFactory.openSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
//處理,假設從客戶端傳遞過來要洗掉的多個引數為一個集合
List<Integer> list = new ArrayList<>();
list.add(1);
//查詢
System.out.println("同一個sqlSession中第一次查詢id=1的資料為"+userDao.findUser(list));
System.out.println("---------------");
//清空SqlSession快取(一級快取)
sqlSession.clearCache();
System.out.println("清空一級快取");
//第二次查詢
System.out.println("---------------");
System.out.println("同一個sqlSession中第二次查詢id=1的資料為"+userDao.findUser(list));
//提交事務
sqlSession.commit();
sqlSession.close();
} catch (IOException e) {
e.printStackTrace();
}
}

3.SqlSession中執行了任何一個update(修改)、delete(洗掉)、insert(新增)操作,都會清空PerpetualCache物件中的資料,但是SqlSession物件仍然可用,
/**
* 快取失效: close clear 執行新增,修改,洗掉操作會清空一級快取
*/
@Test
public void test5() {
try {
Reader reader = Resources.getResourceAsReader("MyBatisConfig.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
SqlSession sqlSession = sessionFactory.openSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
//處理,假設從客戶端傳遞過來要洗掉的多個引數為一個集合
List<Integer> list = new ArrayList<>();
list.add(1);
//查詢
System.out.println("同一個sqlSession中第一次查詢id=1的資料為"+userDao.findUser(list));
System.out.println("---------------");
//執行修改陳述句后快取會失效
User user = new User();
user.setId(1);
user.setAge(20);
userDao.updateUser(user);
System.out.println("執行修改陳述句快取失效");
//第二次查詢
System.out.println("---------------");
System.out.println("同一個sqlSession中第二次查詢id=1的資料為"+userDao.findUser(list));
//提交事務
sqlSession.commit();
sqlSession.close();
} catch (IOException e) {
e.printStackTrace();
}
}

二級快取
二級快取的作用域是SqlSessionFactory級別,整個應用程式只有一個,二級快取區域是根據mapper的namespace劃分的,相同的namespace的mapper查詢的資料快取在同一個區域,如果使用mapper代理方法每一個mapper的namespace都不同,此時可以理解為二級快取區域是根據mapper進行劃分的,
每次查詢都會先從快取區域查找,如果找不到則從資料庫進行查詢,并將查詢到的資料寫入快取,MyBtais內部快取使用HashMap,key為hashCode+sqlid+sql陳述句,value為從查詢出來映射生成的java物件,SqlSession執行任何一個update(修改)、delete(洗掉)、insert(新增)操作commit提交后都會清空快取區域,防止臟讀,
作業模式

配置二級快取
1.在MyBtais全域組態檔中開啟二級快取,具體視版本而言,

<!--mybatis的全域設定-->
<settings>
<!--開啟二級快取,默認是開啟的為true-->
<setting name="cacheEnabled" value="true"/>
<!--配置日志組件-->
<setting name="logImpl" value="LOG4J"/>
<!--開啟駝峰映射-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!--開啟全域懶加載-->
<setting name="lazyLoadTriggerMethods" value="true"/>
</settings>
2.POJO序列化,將所有的POJO類(bean)實作序列化介面java.io.Serializable,
package com.cwd.mybatis.bean;
import org.apache.ibatis.type.Alias;
import java.io.Serializable;
import java.util.Date;
@Alias("User")
public class User implements Serializable {
//生成物體類序列化id
private static final long serialVersionUID = -7383964035746655660L;
private Integer id;
private String name;//姓名
private Integer age;//年齡
private Date birthday;//生日
public Integer getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", birthday=" + birthday +
'}';
}
}
3.配置映射檔案
在Mapper.xml映射檔案中添加cache標簽,表示次mapper開啟二級快取,
<!--
表示此namespace使用二級快取
cache標簽的屬性:
eviction="LRU" :清除策略,默認為LRU,移除最長時間不被使用的物件,
flushInterval="60000" :重繪間隔,以毫秒為單位的合理時間量
size="512" :參考數目
readOnly="true" :只讀的快取會給所有呼叫者回傳快取物件的相同實體
-->
<cache></cache>
<!--按照學號迭代查詢-->
<!--
二級快取
屬性useCache="false",sql陳述句自己可以決定是否使用二級快取
屬性flushCache="false",sql陳述句自己可以決定是否重繪快取,多用與新增,修改,洗掉陳述句
-->
<select id="findUser" resultType="User">
SELECT * FROM t_user WHERE id in
<foreach collection="list" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
測驗
/**
* 二級快取是SqlSessionFactory級別的,整個應用程式只有一個
* 以namespace劃分快取區域
*/
@Test
public void test6() {
try {
Reader reader = Resources.getResourceAsReader("MyBatisConfig.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
//SqlSession1,使用SqlSession查詢第一次查詢資料
SqlSession sqlSession1 = sessionFactory.openSession();
UserDao userDao1 = sqlSession1.getMapper(UserDao.class);
//處理,假設從客戶端傳遞過來要洗掉的多個引數為一個集合
List<Integer> list1 = new ArrayList<>();
list1.add(1);
list1.add(2);
System.out.println("SqlSession1查詢id=1,2的資料為"+userDao1.findUser(list1));
sqlSession1.commit();
sqlSession1.close();//SqlSession關閉時會將資料寫入二級快取
System.out.println("----------------------------------");
//SqlSession2,使用SqlSession查詢第二次查詢資料
SqlSession sqlSession2 = sessionFactory.openSession();
UserDao userDao2 = sqlSession2.getMapper(UserDao.class);
//處理,假設從客戶端傳遞過來要洗掉的多個引數為一個集合
List<Integer> list2 = new ArrayList<>();
list2.add(1);
list2.add(2);
System.out.println("SqlSession2查詢id=1,2的資料為"+userDao2.findUser(list1));
sqlSession2.commit();
sqlSession2.close();
} catch (IOException e) {
e.printStackTrace();
}
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/282660.html
標籤:其他
上一篇:詳解C語言/C++指標:篇1
