1. 程式人生 > >MyBatis快取之一級快取

MyBatis快取之一級快取

1 快取物件

不跨session:

package com.rl.test;

import java.io.InputStream;

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.Before;
import org.junit.Test;

import com.rl.model1.Person;

public class MyBatisTest10 {

    SqlSessionFactory sqlSessionFactory;
    
    @Before
    public void setUp() throws Exception {
        InputStream in = Resources.getResourceAsStream("sqlMapConfig.xml");
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
    }

    @Test
    public void test() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //發出sql語句
        Person person1 = sqlSession.selectOne("com.rl.mapper.PersonMapper.selectPersonById", 1);
        //不發出sql語句, 直接在快取中查詢
        Person person2 = sqlSession.selectOne("com.rl.mapper.PersonMapper.selectPersonById", 1);
        System.out.println(person1);
        System.out.println(person2);
    }
}

跨session:

@Test
    public void test1() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //發出sql語句
        sqlSession.selectOne("com.rl.mapper.PersonMapper.selectPersonById", 1);
        sqlSession.close();
        
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        //再次發出sql語句
        sqlSession2.selectOne("com.rl.mapper.PersonMapper.selectPersonById", 1);
        sqlSession2.close();
    }

以上例子說明MyBatis的一級快取是不能跨session的, 一旦跨session了, 則必須重新發出sql語句查詢資料庫

另外, 一級快取有個特點, 就是不受配置, 都是MyBatis自己管理, 我們只負責用

2 快取集合

@Test
    public void test2() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //發出sql語句
        List<Person> pList1 = sqlSession.selectList("selectPersonAll");
        //不發出sql語句
        List<Person> pList2 = sqlSession.selectList("selectPersonAll");
        for(Person p: pList1){
            System.out.println(p);
        }
        for(Person p: pList2){
            System.out.println(p);
        }
    }

假如在這個查詢的過程中後臺的資料被手動修改了, 此時快取是無法得知的, 依然會輸出快取中的內容

如果是程式修改的後臺資料, 則MyBatis是能夠感知到, 因為涉及到了快取重新整理

1 在查詢物件時修改資料:

@Test
    public void test3() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //發出sql語句
        Person p = sqlSession.selectOne("com.rl.mapper.PersonMapper.selectPersonById", 1);
        
        p.setName("火星");
        sqlSession.update("com.rl.mapper.PersonMapper.dynamicUpdate", p);
        sqlSession.commit();
        
        //重新發出sql語句
        Person p1 = sqlSession.selectOne("com.rl.mapper.PersonMapper.selectPersonById", 1);
        
        //兩次輸出的都是新的資料
        System.out.println(p);
        System.out.println(p1);
    }

由於update了資料庫, MyBatis將快取中的資料全部清空, 所以第二次查詢時必須要重新發出sql語句, 並且輸出的都是新的資料

2 在查詢集合時修改資料:

測試程式碼:

@Test
    public void test4() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        List<Person> pList1 = sqlSession.selectList("selectPersonAll");
        
        Person person = new Person();
        person.setName("王五");
        person.setGender(2);
        person.setBirthday(new Date());
        person.setPersonAddr("紐約");
        sqlSession.insert("com.rl.mapper.PersonMapper.insert", person);
        sqlSession.commit();
        
        List<Person> pList2 = sqlSession.selectList("selectPersonAll");
        //輸出的依舊是原先的資料
        for(Person p: pList1){
            System.out.println(p);
        }
        //輸出的是最新的資料
        for(Person p: pList2){
            System.out.println(p);
        }
    }

結果輸出:

Person [personId=1, name=海地, gender=1, personAddr=天津, birthday=Fri Sep 07 00:00:00 CST 2018, orderList=null]
Person [personId=2, name=晁蓋, gender=2, personAddr=上海, birthday=Mon Sep 10 00:00:00 CST 2018, orderList=null]
Person [personId=4, name=黃忠, gender=1, personAddr=上海, birthday=Sun Sep 09 00:00:00 CST 2018, orderList=null]


Person [personId=1, name=海地, gender=1, personAddr=天津, birthday=Fri Sep 07 00:00:00 CST 2018, orderList=null]
Person [personId=2, name=晁蓋, gender=2, personAddr=上海, birthday=Mon Sep 10 00:00:00 CST 2018, orderList=null]
Person [personId=4, name=黃忠, gender=1, personAddr=上海, birthday=Sun Sep 09 00:00:00 CST 2018, orderList=null]
Person [personId=4000025, name=王五, gender=2, personAddr=紐約, birthday=Tue Sep 11 00:00:00 CST 2018, orderList=null]

但是快取集合跟快取物件有所不同, 快取物件時, 快取一旦修改後被清空, 則原先查詢上來的資料也會同步地修改了, 但是快取集合卻不會, 也就是上面輸出時還是原先的資料, 只有第二次查詢集合時才是最新的資料

3 在查詢時刪除資料:

對於集合的情況跟插入新資料一樣:

測試程式碼:

@Test
    public void test5() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        List<Person> pList1 = sqlSession.selectList("selectPersonAll");
        
        Person person = sqlSession.selectOne("com.rl.mapper.PersonMapper.selectPersonById", 1);
        sqlSession.delete("com.rl.mapper.PersonMapper.delete", person);
        sqlSession.commit();
        
        List<Person> pList2 = sqlSession.selectList("selectPersonAll");
        for(Person p: pList1){
            System.out.println(p);
        }
        for(Person p: pList2){
            System.out.println(p);
        }
    }

輸出結果:

Person [personId=1, name=海地, gender=1, personAddr=天津, birthday=Fri Sep 07 00:00:00 CST 2018, orderList=null]
Person [personId=2, name=晁蓋, gender=2, personAddr=上海, birthday=Mon Sep 10 00:00:00 CST 2018, orderList=null]
Person [personId=4, name=黃忠, gender=1, personAddr=上海, birthday=Sun Sep 09 00:00:00 CST 2018, orderList=null]
Person [personId=4000025, name=王五, gender=2, personAddr=紐約, birthday=Tue Sep 11 00:00:00 CST 2018, orderList=null]


Person [personId=2, name=晁蓋, gender=2, personAddr=上海, birthday=Mon Sep 10 00:00:00 CST 2018, orderList=null]
Person [personId=4, name=黃忠, gender=1, personAddr=上海, birthday=Sun Sep 09 00:00:00 CST 2018, orderList=null]
Person [personId=4000025, name=王五, gender=2, personAddr=紐約, birthday=Tue Sep 11 00:00:00 CST 2018, orderList=null]

對於查詢物件時將資料刪除的情況則略有不同:

@Test
    public void test6() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        Person person1 = sqlSession.selectOne("com.rl.mapper.PersonMapper.selectPersonById", 2);
        
        Person person = sqlSession.selectOne("com.rl.mapper.PersonMapper.selectPersonById", 2);
        sqlSession.delete("com.rl.mapper.PersonMapper.delete", person);
        sqlSession.commit();
        
        Person person2 = sqlSession.selectOne("com.rl.mapper.PersonMapper.selectPersonById", 2);
        //還是能夠輸出已經被刪除的資料
        System.out.println(person1);
        //輸出null
        System.out.println(person2);
    }