來源:亮哥168 發(fā)布時(shí)間:2019-03-30 17:39:04 閱讀量:1839
* 有問題可以參加Java技術(shù)交流群:839366464
MyBatis緩存介紹
1 MyBatis 提供了一級(jí)緩存和二級(jí)緩存的支持
2 一級(jí)緩存: 基于PerpetualCache 的 HashMap本地緩存,其存儲(chǔ)作用域?yàn)?Session,當(dāng) Session flush 或 close 之后,該Session中的所有 Cache 就將清空。
3. 二級(jí)緩存與一級(jí)緩存其機(jī)制相同,默認(rèn)也是采用 PerpetualCache,HashMap存儲(chǔ),不同在于其存儲(chǔ)作用域?yàn)?Mapper(Namespace)
4. 對(duì)于緩存數(shù)據(jù)更新機(jī)制,當(dāng)某一個(gè)作用域(一級(jí)緩存Session/二級(jí)緩存Namespaces)的進(jìn)行了 C/U/D 操作后,默認(rèn)該作用域下所有 select 中的緩存將被clear。
5.支持自定義緩存
* 一級(jí)緩存
MyBatis 默認(rèn)開啟了一級(jí)緩存,一級(jí)緩存是在SqlSession 層面進(jìn)行緩存的。即,同一個(gè)SqlSession ,多次調(diào)用同一個(gè)Mapper和同一個(gè)方法的同一個(gè)參數(shù),只會(huì)進(jìn)行一次數(shù)據(jù)庫查詢,然后把數(shù)據(jù)緩存到緩沖中,以后直接先從緩存中取出數(shù)據(jù),不會(huì)直接去查數(shù)據(jù)庫。
@Test
public void test12(){
SqlSession session = MyBatisUtils.getSqlSession();
// 測試一級(jí)緩存
UserMapper mapper = session.getMapper(UserMapper.class);
// 進(jìn)行兩次相同的查詢操作
List<User> users = mapper.findUsers();
users = mapper.findUsers();
session.close();
}
不同的SqlSession對(duì)象,會(huì)再次發(fā)送到SQL到數(shù)據(jù)庫去執(zhí)行
@Test
public void test13(){
SqlSession session = MyBatisUtils.getSqlSession();
// 測試一級(jí)緩存
UserMapper mapper = session.getMapper(UserMapper.class);
// 不同sqlSession對(duì)象測試
List<User> users = mapper.findUsers();
session.commit();
// 獲得一個(gè)新的SqlSession 對(duì)象
session = MyBatisUtils.getSqlSession();
mapper = session.getMapper(UserMapper.class);
users = mapper.findUsers();
session.close();
}
* 在CUD的時(shí)候會(huì)清除緩存
@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);
}
* 二級(jí)緩存
假如需要不同sqlSession對(duì)象也要緩存的話,需要開啟二級(jí)緩存,是緩存在SqlSessionFactory層面給各個(gè)SqlSession 對(duì)象共享。默認(rèn)二級(jí)緩存是不開啟的,需要手動(dòng)進(jìn)行配置。
配置:
<cache/>
如果這樣配置的話,很多其他的配置就會(huì)被默認(rèn)進(jìn)行,如:
映射文件所有的select 語句會(huì)被緩存
映射文件的所有的insert、update和delete語句會(huì)刷新緩存
緩存會(huì)使用默認(rèn)的Least Recently Used(LRU,最近最少使用原則)的算法來回收緩存空間
根據(jù)時(shí)間表,比如No Flush Interval,(CNFI,沒有刷新間隔),緩存不會(huì)以任何時(shí)間順序來刷新
緩存會(huì)存儲(chǔ)列表集合或?qū)ο螅o論查詢方法返回什么)的1024個(gè)引用
緩存會(huì)被視為是read/write(可讀/可寫)的緩存,意味著對(duì)象檢索不是共享的,而且可以很安全的被調(diào)用者修改,不干擾其他調(diào)用者或縣城所作的潛在修改
* 開啟緩存的對(duì)象需要序列化
<mapper namespace="com.hx.hx02.mapper.UserMapper">
<cache/>
...
</mapper>
<cache eviction="LRU" flushInterval="100000" size="" readOnly="true"/>
各個(gè)屬性意義如下:
eviction:緩存回收策略
- LRU:最少使用原則,移除最長時(shí)間不使用的對(duì)象
- FIFO:先進(jìn)先出原則,按照對(duì)象進(jìn)入緩存順序進(jìn)行回收
- SOFT:軟引用,移除基于垃圾回收器狀態(tài)和軟引用規(guī)則的對(duì)象
- WEAK:弱引用,更積極的移除移除基于垃圾回收器狀態(tài)和弱引用規(guī)則的對(duì)象
flushInterval:刷新時(shí)間間隔,單位為毫秒。如果不配置,那么只有在進(jìn)行數(shù)據(jù)庫修改操作才會(huì)被動(dòng)刷新緩存區(qū)
size:引用額數(shù)目,代表緩存最多可以存儲(chǔ)的對(duì)象個(gè)數(shù)
readOnly:是否只讀,如果為true,則所有相同的sql語句返回的是同一個(gè)對(duì)象(有助于提高性能,但并發(fā)操作同一條數(shù)據(jù)時(shí),可能不安全),如果設(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>
二級(jí)緩存默認(rèn)會(huì)在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();
// 獲得一個(gè)新的SqlSession 對(duì)象
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)+"緩存的大?。?/span>"+cache.size());
return cache.get(key);
} finally {
lock.readLock().unlock();
}
}
@Override
public Object removeObject(Object key) {
System.out.println("移除緩存對(duì)象:" + 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("獲取緩存大?。?/span>" + cache.size());
return cache.size();
}
@Override
public ReadWriteLock getReadWriteLock() {
System.out.println("獲取鎖對(duì)象?。?!");
return lock;
}
}
<cache type="com.hx.hx02.cache.LruCache"/>
* Mybatis細(xì)節(jié)
* 配置mapper方式(包的方式)
<mappers>
<package name="com.hx.hx02.mapper"/>
</mappers>
* 配置package的方式出錯(cuò)的解決方案
解決方案,原來是IDEA maven項(xiàng)目默認(rèn)不會(huì)把src下除java文件外的文件打包到classes文件夾下,需要在maven中增加配置如下
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<!--默認(rèn)是true-->
<!--<filtering>true</filtering>-->
</resource>
</resources>
* 實(shí)體bean的配置
<typeAliases>
<package name="com.hx.hx02.bean"></package>
</typeAliases>
在線
客服
客服
熱線
7*24小時(shí)客服服務(wù)熱線
關(guān)注
微信
關(guān)注官方微信