來源:亮哥168 發(fā)布時間:2019-03-30 17:39:04 閱讀量:1421
* 有問題可以參加Java技術(shù)交流群:839366464
MyBatis緩存介紹
1 MyBatis 提供了一級緩存和二級緩存的支持
2 一級緩存: 基于PerpetualCache 的 HashMap本地緩存,其存儲作用域為 Session,當(dāng) Session flush 或 close 之后,該Session中的所有 Cache 就將清空。
3. 二級緩存與一級緩存其機(jī)制相同,默認(rèn)也是采用 PerpetualCache,HashMap存儲,不同在于其存儲作用域為 Mapper(Namespace)
4. 對于緩存數(shù)據(jù)更新機(jī)制,當(dāng)某一個作用域(一級緩存Session/二級緩存Namespaces)的進(jìn)行了 C/U/D 操作后,默認(rèn)該作用域下所有 select 中的緩存將被clear。
5.支持自定義緩存
* 一級緩存
MyBatis 默認(rèn)開啟了一級緩存,一級緩存是在SqlSession 層面進(jìn)行緩存的。即,同一個SqlSession ,多次調(diào)用同一個Mapper和同一個方法的同一個參數(shù),只會進(jìn)行一次數(shù)據(jù)庫查詢,然后把數(shù)據(jù)緩存到緩沖中,以后直接先從緩存中取出數(shù)據(jù),不會直接去查數(shù)據(jù)庫。
@Test
public void test12(){
SqlSession session = MyBatisUtils.getSqlSession();
// 測試一級緩存
UserMapper mapper = session.getMapper(UserMapper.class);
// 進(jìn)行兩次相同的查詢操作
List<User> users = mapper.findUsers();
users = mapper.findUsers();
session.close();
}
不同的SqlSession對象,會再次發(fā)送到SQL到數(shù)據(jù)庫去執(zhí)行
@Test
public void test13(){
SqlSession session = MyBatisUtils.getSqlSession();
// 測試一級緩存
UserMapper mapper = session.getMapper(UserMapper.class);
// 不同sqlSession對象測試
List<User> users = mapper.findUsers();
session.commit();
// 獲得一個新的SqlSession 對象
session = MyBatisUtils.getSqlSession();
mapper = session.getMapper(UserMapper.class);
users = mapper.findUsers();
session.close();
}
* 在CUD的時候會清除緩存
@Test
public void test36() throws Exception {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Integer> ids=new ArrayList<Integer>();
ids.add(100001);
ids.add(100002);
ids.add(100003);
List<Student> students = mapper.getStudentsByListIds(ids);
Student student=new Student();
student.setSid(100002);
student.setSname("小黑");
student.setSsex('男');
student.setSage(22);
mapper.updateStudent(student);
sqlSession.commit();
students = mapper.getStudentsByListIds(ids);
System.out.println(students);
MyBatisUtils.close(sqlSession);
}
* 二級緩存
假如需要不同sqlSession對象也要緩存的話,需要開啟二級緩存,是緩存在SqlSessionFactory層面給各個SqlSession 對象共享。默認(rèn)二級緩存是不開啟的,需要手動進(jìn)行配置。
配置:
<cache/>
如果這樣配置的話,很多其他的配置就會被默認(rèn)進(jìn)行,如:
映射文件所有的select 語句會被緩存
映射文件的所有的insert、update和delete語句會刷新緩存
緩存會使用默認(rèn)的Least Recently Used(LRU,最近最少使用原則)的算法來回收緩存空間
根據(jù)時間表,比如No Flush Interval,(CNFI,沒有刷新間隔),緩存不會以任何時間順序來刷新
緩存會存儲列表集合或?qū)ο螅o論查詢方法返回什么)的1024個引用
緩存會被視為是read/write(可讀/可寫)的緩存,意味著對象檢索不是共享的,而且可以很安全的被調(diào)用者修改,不干擾其他調(diào)用者或縣城所作的潛在修改
* 開啟緩存的對象需要序列化
<mapper namespace="com.hx.hx02.mapper.UserMapper">
<cache/>
...
</mapper>
<cache eviction="LRU" flushInterval="100000" size="" readOnly="true"/>
各個屬性意義如下:
eviction:緩存回收策略
- LRU:最少使用原則,移除最長時間不使用的對象
- FIFO:先進(jìn)先出原則,按照對象進(jìn)入緩存順序進(jìn)行回收
- SOFT:軟引用,移除基于垃圾回收器狀態(tài)和軟引用規(guī)則的對象
- WEAK:弱引用,更積極的移除移除基于垃圾回收器狀態(tài)和弱引用規(guī)則的對象
flushInterval:刷新時間間隔,單位為毫秒。如果不配置,那么只有在進(jìn)行數(shù)據(jù)庫修改操作才會被動刷新緩存區(qū)
size:引用額數(shù)目,代表緩存最多可以存儲的對象個數(shù)
readOnly:是否只讀,如果為true,則所有相同的sql語句返回的是同一個對象(有助于提高性能,但并發(fā)操作同一條數(shù)據(jù)時,可能不安全),如果設(shè)置為false,則相同的sql,后面訪問的是cache的clone副本。
*細(xì)節(jié)
useCache 的使用:select 有權(quán)利選擇要不要被緩存
<select id="findUsers" resultType="com.hx.hx02.bean.User" useCache="false">
SELECT *
FROM user;
</select>
二級緩存默認(rèn)會在insert、update、delete操作后刷新緩存
@Test
public void test14(){
SqlSession session = MyBatisUtils.getSqlSession();
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> users = mapper.findUsers();
User user=new User();
user.setUsername("xiao123");
user.setSex('男');
user.setPsw("123");
mapper.insertUser(user);
session.commit();
// 獲得一個新的SqlSession 對象
session = MyBatisUtils.getSqlSession();
mapper = session.getMapper(UserMapper.class);
users = mapper.findUsers();
session.commit();
session.close();
}
flushCache:可以配置要不要刷新緩存
<insert id="insertUser" parameterType="com.hx.hx02.bean.User" flushCache="false">
INSERT INTO USER(username, psw, sex)
VALUES (#{username}, #{psw}, #{sex});
</insert>
<cache eviction="LRU" flushInterval="100" size="1" readOnly="true"/>
public void test37() throws Exception {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Integer> ids=new ArrayList<Integer>();
ids.add(100001);
ids.add(100002);
ids.add(100003);
List<Student> students = mapper.getStudentsByListIds(ids);
sqlSession.commit();
sqlSession = MyBatisUtils.getSqlSession();
mapper = sqlSession.getMapper(StudentMapper.class);
HashMap<String,Object> map=new HashMap<String,Object>();
map.put("ssex","男");
students = mapper.getStudentsByParams(map);
sqlSession.commit();
sqlSession = MyBatisUtils.getSqlSession();
mapper = sqlSession.getMapper(StudentMapper.class);
map.put("ssex","男");
students = mapper.getStudentsByParams(map);
sqlSession.commit();
sqlSession = MyBatisUtils.getSqlSession();
mapper = sqlSession.getMapper(StudentMapper.class);
mapper.getStudentsByListIds(ids);
sqlSession.commit();
MyBatisUtils.close(sqlSession);
}
* 自定義緩存(擴(kuò)展)
* mybatis 自帶的緩存:
* public class PerpetualCache implements Cache
* 自定義LRUCache緩存
public class LruCache implements Cache {
private String id;
private ReadWriteLock lock = new ReentrantReadWriteLock();
private LinkedHashMap cache = new LinkedHashMap(16, 0.75f, true);
public LruCache() {
System.out.println("LruCache 初始化");
}
public LruCache(String id) {
System.out.println("LruCache 初始化:" + id);
this.id = id;
}
@Override
public String getId() {
return this.id;
}
@Override
public void putObject(Object key, Object value) {
System.out.println("放進(jìn)緩存了....");
try {
lock.writeLock().lock();
cache.put(key, value);
} finally {
lock.writeLock().unlock();
}
}
@Override
public Object getObject(Object key) {
lock.readLock().lock();
try {
System.out.println("獲得緩存:"+cache.get(key)+"緩存的大小:"+cache.size());
return cache.get(key);
} finally {
lock.readLock().unlock();
}
}
@Override
public Object removeObject(Object key) {
System.out.println("移除緩存對象:" + key);
try {
lock.writeLock().lock();
return cache.remove(key);
} finally {
lock.writeLock().unlock();
}
}
@Override
public void clear() {
System.out.println("清除緩存!");
cache.clear();
}
@Override
public int getSize() {
System.out.println("獲取緩存大??!" + cache.size());
return cache.size();
}
@Override
public ReadWriteLock getReadWriteLock() {
System.out.println("獲取鎖對象?。?!");
return lock;
}
}
<cache type="com.hx.hx02.cache.LruCache"/>
* Mybatis細(xì)節(jié)
* 配置mapper方式(包的方式)
<mappers>
<package name="com.hx.hx02.mapper"/>
</mappers>
* 配置package的方式出錯的解決方案
解決方案,原來是IDEA maven項目默認(rèn)不會把src下除java文件外的文件打包到classes文件夾下,需要在maven中增加配置如下
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<!--默認(rèn)是true-->
<!--<filtering>true</filtering>-->
</resource>
</resources>
* 實體bean的配置
<typeAliases>
<package name="com.hx.hx02.bean"></package>
</typeAliases>