mybatis 15: 快取

作用

  • 當對某些數據的查詢請求頻繁,且數據不經常修改時,使用快取機制可以提高查詢效率

注意

  • mybatis專註於sql查詢,數據映射
  • 快取問題應該交給專門負責快取的其他第三方框架

mybatis快取執行流程

image

mybatis一級和二級快取

image

  • 一級快取作用域:sqlSession對象
  • 二級快取作用域:Mapper.xml文件
  • 查詢順序:先二級快取,再一級快取,最後查資料庫

mybatis一級快取

  • mybatis默認開啟一級快取

一級快取測試

package com.example.mapper;

import com.example.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;

public class TestUsersMapper {

    //SqlSession對象
    SqlSession sqlSession;

    //mybatis動態代理對象
    UsersMapper usersMapper;

    //獲取SqlSession
    @Before
    public void getSqlSession() throws IOException {
        //讀取核心配置文件
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //創建SqlSessionFactory對象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //獲取SqlSession
        sqlSession = factory.openSession();
        //獲取mybatis動態代理對象
        usersMapper = sqlSession.getMapper(UsersMapper.class);
    }

    //歸還SqlSession
    @After
    public void closeSession(){
        sqlSession.close();
    }

    //測試mybatis一級快取
    @Test
    public void testOneLevelCache(){
        //兩次查詢,id相同時
        User u1 = usersMapper.getById(1);
        System.out.println("第1次查詢結果: " + u1);
        System.out.println("----------------------");
        User u2 = usersMapper.getById(1);
        System.out.println("第2次查詢結果: " + u2);
        System.out.println("------------------------");
        if(u1 == u2){
            System.out.println("兩個對象的記憶體地址相同");
        }else{
            System.out.println("兩個對象的記憶體地址不同");
        }
        System.out.println("**************************************************");
        //兩次查詢,id不同時
        User u3 = usersMapper.getById(2);
        System.out.println("第1次查詢結果: " + u3);
        System.out.println("----------------------");
        User u4 = usersMapper.getById(5);
        System.out.println("第2次查詢結果: " + u4);
        System.out.println("------------------------");
        if(u3 == u4){
            System.out.println("兩個對象的記憶體地址相同");
        }else{
            System.out.println("兩個對象的記憶體地址不同");
        }
    }
}

測試結果

==>  Preparing: select id, username, birthday, sex, address from users where id=?
==> Parameters: 1(Integer)
<==    Columns: id, username, birthday, sex, address
<==        Row: 1, 荷包蛋, 2002-08-23, 女, 黑河
<==      Total: 1
第1次查詢結果: Users{id=1, userName='荷包蛋', birthday=Fri Aug 23 00:00:00 CST 2002, sex='女', address='黑河'}
----------------------
第2次查詢結果: Users{id=1, userName='荷包蛋', birthday=Fri Aug 23 00:00:00 CST 2002, sex='女', address='黑河'}
------------------------
兩個對象的記憶體地址相同
**************************************************
==>  Preparing: select id, username, birthday, sex, address from users where id=?
==> Parameters: 2(Integer)
<==    Columns: id, username, birthday, sex, address
<==        Row: 2, 小王, 2001-07-12, 1, 蕪湖市
<==      Total: 1
第1次查詢結果: Users{id=2, userName='小王', birthday=Thu Jul 12 00:00:00 CST 2001, sex='1', address='蕪湖市'}
----------------------
==>  Preparing: select id, username, birthday, sex, address from users where id=?
==> Parameters: 5(Integer)
<==    Columns: id, username, birthday, sex, address
<==        Row: 5, 段, 2001-03-10, 1, 太原
<==      Total: 1
第2次查詢結果: Users{id=5, userName='段', birthday=Sat Mar 10 00:00:00 CST 2001, sex='1', address='太原'}
------------------------
兩個對象的記憶體地址不同

結果分析

  • 以上u1到u4同屬於一個sqlSession域,因為下面程式碼只執行過一次,sqlSession只獲取過一個,後面操作都是在該sqlSession對象的基礎上進行的
//獲取SqlSession
sqlSession = factory.openSession();
  • 當兩次查詢的id相同時,第一次查詢開啟了資料庫連接,第二次沒有再開啟資料庫連接,而是從快取中獲取,且兩個對象記憶體地址相同
    • 其實u1和u2本質上是sqlSession域中的同一個對象
  • 當兩次查詢的id不同時,兩次查詢都開啟了資料庫連接,且兩個對象記憶體地址不同
    • 其實u3和u4本質上是sqlSession域中的不同對象
Tags: