05.SSM框架集~Mybatis(三)
本文是上一篇文章的後續,詳情點擊該鏈接
Mybatis 1 ~ 3 源碼 提取碼:pmbr
緩存
緩存(cache),原始意義是指訪問速度比一般隨機存取存儲器(RAM)快的一種高速存儲器,通常它不像系統主存那樣使用DRAM技術,而使用昂貴但較快速的SRAM技術。緩存的設置是所有現代計算機系統發揮高性能的重要因素之一。
是一種臨時存儲少量數據至內存或者是磁盤的一種技術.減少數據的加載次數,可以降低工作量,提高程序響應速度
緩存的重要性是不言而喻的。mybatis的緩存將相同查詢條件的SQL語句執行一遍後所得到的結果存在內存或者某種緩存介質當中,當下次遇到一模一樣的查詢SQL時候不在執行SQL與數據庫交互,而是直接從緩存中獲取結果,減少服務器的壓力;尤其是在查詢越多、緩存命中率越高的情況下,使用緩存對性能的提高更明顯。
MyBatis允許使用緩存,緩存一般放置在高速讀/寫的存儲器上,比如服務器的內存,能夠有效的提供系統性能。MyBatis分爲一級緩存和二級緩存,同時也可配置關於緩存設置。
一級存儲是SqlSession上的緩存,二級緩存是在SqlSessionFactory(namespace)上的緩存。默認情況下,MyBatis開啓一級緩存,沒有開啓二級緩存。當數據量大的時候可以藉助一些第三方緩存框架或Redis緩存來協助保存Mybatis的二級緩存數據。
一級緩存
一級存儲是SqlSession上的緩存,默認開啓,是一種內存型緩存,不要求實體類對象實現Serializable接口。s下面在沒有任何配置的情況下,測試一級緩存。
接口
Student FindBySon(String son);
Mapper
<select id="FindBySon" resultType="student">
select * from student where son = #{son}
</select>
Java
public static void cache(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Student student = mapper.FindBySon("666666");
System.out.println(student);
//假如此處做了增刪改
/*commit方法會刷新一級緩存
* 和事務是否自動提交沒有關係
* */
sqlSession.commit();
StudentMapper mapper2 = sqlSession.getMapper(StudentMapper.class);
Student student2 = mapper2.FindBySon("666666");
System.out.println(student2);
/*
* 多個同namespace下的mapper 只要來自於同一個sqlsession就可以公用以及緩存
* */
System.out.println(mapper==mapper2);
sqlSession.close();
}
二級緩存
二級緩存是以namespace爲標記的緩存,可以是由一個SqlSessionFactory創建的SqlSession之間共享緩存數據。默認並不開啓。下面的代碼中創建了兩個SqlSession,執行相同的SQL語句,嘗試讓第二個SqlSession使用第一個SqlSession查詢後緩存的數據。
public static void caches(){
/*使用第一個sqlsession去查詢數據*/
SqlSession sqlSession = SqlSessionUtil.getSqlSession(false);
StudentMapper mapper = sqlSession.getMapper( StudentMapper.class);
Student student = mapper.FindBySon("666666");
System.out.println(student);
// sqlSession.commit();
sqlSession.close();
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
/*使用第二個sqlsession查詢數據*/
SqlSession sqlSession2 = SqlSessionUtil.getSqlSession(false);
StudentMapper mapper2 = sqlSession2.getMapper( StudentMapper.class);
Student student2 = mapper2.FindBySon("666666");
System.out.println(student2);
sqlSession2.close();
}
注意其中的commit(),執行該命令後纔會將該SqlSession的查詢結果從一級緩存中放入二級緩存,供其他SqlSession使用。另外執行SqlSession的close()也會將該SqlSession的查詢結果從一級緩存中放入二級緩存。兩種方式區別在當前SqlSession是否關閉了。
執行結果顯示進行了兩次對數據庫的SQL查詢,說明二級緩存並沒有開啓。需要進行如下步驟完成開啓。
(1) 全局開關:在mybatis.xml文件中的標籤配置開啓二級緩存
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
(2) 分開關:在要開啓二級緩存的mapper文件中開啓緩存:
<mapper namespace="com.alvin.studentmapper.StudentMapper">
<cache/>
</mapper>
(3) 二級緩存未必完全使用內存,有可能佔用硬盤存儲,緩存中存儲的JavaBean對象必須實現序列化接口,
public class Student implements Serializable {
private String son;
private String realname;
private String password;
private String classname;
private Double score;
}
經過設置後,查詢結果如圖所示。發現第一個SqlSession會首先去二級緩存中查找,如果不存在,就查詢數據庫,在commit()或者close()的時候將數據放入到二級緩存。第二個SqlSession執行相同SQL語句查詢時就直接從二級緩存中獲取了。
注意:
(1) MyBatis的二級緩存的緩存介質有多種多樣,而並不一定是在內存中,所以需要對JavaBean對象實現序列化接口。
(2) 二級緩存是以 namespace 爲單位的,不同 namespace 下的操作互不影響
(3) 加入Cache元素後,會對相應命名空間所有的select元素查詢結果進行緩存,而其中的insert、update、delete在操作是會清空整個namespace的緩存。
(4) cache 有一些可選的屬性 type, eviction, flushInterval, size, readOnly, blocking。
<cache type="" readOnly="" eviction=""flushInterval=""size=""blocking=""/>
屬性 | 含義 | 默認值 |
type | 自定義緩存類,要求實現org.apache.ibatis.cache.Cache接口 | null |
readOnly | 是否只讀 true:給所有調用者返回緩存對象的相同實例。因此這些對象不能被修改。這提供了很重要的性能優勢。 false:會返回緩存對象的拷貝(通過序列化) 。這會慢一些,但是安全 | false |
eviction | 緩存策略
LRU(默認) – 最近最少使用:移除最長時間不被使用的對象。 FIFO – 先進先出:按對象進入緩存的順序來移除它們。 SOFT – 軟引用:基於垃圾回收器狀態和軟引用規則移除對象。 WEAK – 弱引用:更積極地基於垃圾收集器狀態和弱引用規則移除對象。 |
LRU |
flushInterval | 刷新間隔,毫秒爲單位。默認爲null,也就是沒有刷新間隔,只有執行update、insert、delete語句纔會刷新 | null |
size | 緩存對象個數 | 1024 |
blocking | 是否使用阻塞性緩存BlockingCache true:在查詢緩存時鎖住對應的Key,如果緩存命中了則會釋放對應的鎖,否則會在查詢數據庫以後再釋放鎖,保證只有一個線程到數據庫中查找指定key對應的數據 false:不使用阻塞性緩存,性能更好 |
false |
(5)如果在加入Cache元素的前提下讓個別select 元素不使用緩存,可以使用useCache屬性,設置爲false。useCache控制當前sql語句是否啓用緩存 flushCache控制當前sql執行一次後是否刷新緩存
<select id="FindBySon()" resultType="student" useCache="true" flushCache="false">
MyBatis註解開發
MyBatis編寫SQL除了使用Mapper.xml還可以使用註解完成。當可以使用Auto Mapping時使用註解非常簡單,不需要頻繁的在接口和mapper.xml兩個文件之間進行切換。但是必須配置resultMap時使用註解將會變得很麻煩,這種情況下推薦使用mapper.xml進行配置。
MyBatis支持純註解方式,支持純mapper.xml方式,也支持註解和mapper.xml混合形式。當只有接口沒有mapper.xml時在mybatis.cfg.xml中可以通過加載接口類。如果是混合使用時,使用。此方式一直是官方推薦方式。
如果某個功能同時使用兩種方式進行配置,XML方式將覆蓋註解方式
使用註解完成之前的增刪查改操作
這一次我們只需要一個接口即可,無需StudentMapper.xml
Mapper接口
public interface StudentMapper {
//查詢全部學生信息
@Select("select * from student")
List<Student> FindAll();
//增加學生信息
@Insert("insert into student value(#{son},#{realname},#{password},#{classname},#{score})")
int Insert(Student student);
//刪除學生信息
@Delete("delete from student where son = #{son}")
int delete(String son);
//修改學生信息
@Update("update student set realname = #{realname}, password = #{password},classname = #{classname},score = #{score} where son = #{son};")
int change(Student student);
//查詢單個學生信息
@Select("select * from student where son = #{son};")
Student FindByOn(String son);
//模糊查詢
@Select("select * from student where realname like concat('%',#{realname},'%')")
List<Student> getByName(String realname);
}
代碼測試
public class Test {
public static void main(String[] args) {
//Del();
//FindAll();
//Insert();
//Update();
//Find();
Fin();
}
//模糊查詢
public static void Fin(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//查詢姓名包含張的學生
List<Student> students = mapper.getByName("張");
//遍歷
Iterator iterator = students.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
sqlSession.close();
}
//查詢全部學生信息
public static void FindAll(){
//查詢全部學生信息
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
// 幫助我們生成一個接口下的實現類對象的
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
// 接收數據
List<Student> list = studentMapper.FindAll();
//關閉sqlSession
sqlSession.close();
//遍歷結果
Iterator iterator = list.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
//新增學生信息
public static void Insert(){
//當執行增刪改時,就需要提交True,否則無法完成操作!
SqlSession sqlSession = SqlSessionUtil.getSqlSession(true);
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
//需要新增的信息
Student student = new Student("666666","黃貴根","666666","信息工程學院",533.0);
//調用新增
int n = studentMapper.Insert(student);
//關閉sqlSession
sqlSession.close();
//處理結果
String str = n > 0 ? "新增成功!" : "新增失敗!";
System.out.println(str);
}
//修改學生信息
public static void Update(){
//當執行增刪改時,就需要提交True,否則無法完成操作!
SqlSession sqlSession = SqlSessionUtil.getSqlSession(true);
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
//需要修改的信息
Student student = new Student("666666","黃貴根","123456","信息工程學院",600.0);
//調用修改
int n = studentMapper.change(student);
//關閉sqlSession
sqlSession.close();
//處理結果
String str = n > 0 ? "修改成功!" : "修改失敗!";
System.out.println(str);
}
//刪除學生信息
public static void Del(){
//當執行增刪改時,就需要提交True,否則無法完成操作!
SqlSession sqlSession = SqlSessionUtil.getSqlSession(true);
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
//調用刪除
int n = studentMapper.delete("666666");
//關閉sqlSession
sqlSession.close();
//處理結果
String str = n > 0 ? "刪除成功!" : "刪除失敗!";
System.out.println(str);
}
//查找學生信息
public static void Find(){
//查詢操作則無需提交
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
//調用查詢
Student student = studentMapper.FindByOn("154787");
//關閉sqlSession
sqlSession.close();
//處理結果
String str = student != null ? student.toString() : "沒找到!";
System.out.println(str);
}
}
註解和XML對比:
XML:
1.類和類之間的解耦
2.利於修改。直接修改XML文件,無需到源代碼中修改。
3.配置集中在XML中,對象間關係一目瞭然,利於快速瞭解項目和維護
4.容易和其他系統進行數據交交換
註解:
1.簡化配置
2.使用起來直觀且容易,提升開發效率
3.類型安全,編譯器進行校驗,不用等到運行期纔會發現錯誤。
4.註解的解析可以不依賴於第三方庫,可以之間使用Java自帶的反射