05.SSM框架集~Mybatis(三)

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自帶的反射

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章