1. 程式人生 > >MyBatis-緩存機制

MyBatis-緩存機制

employ pre 查詢信息 ear lec 先進先出 temp code test

MyBatis 包含一個非常強大的查詢緩存特性,它可以非常方便地配置和定制。緩存可以極大的提升查詢效率。
MyBatis系統中默認定義了兩級緩存。
一級緩存和二級緩存。
一級緩存:(本地緩存):SqlSession級別的緩存,一級緩存是一致開啟的,沒法關閉。方法之間不共用!
與數據庫同一次會話期間查詢到的數據放在本地緩存中。
以後如果需要獲取相同的數據,直接從緩存中拿,沒必要再去查詢數據庫;
二級緩存(全局緩存):

–1、默認情況下,只有一級緩存(SqlSession級別的緩存,也稱為本地緩存)開啟。
–2、二級緩存需要手動開啟和配置,他是基於namespace級別的緩存。
–3、為了提高擴展性。MyBatis定義了緩存接口Cache。我們可以通過實現Cache接口來自定義二級緩存。

案例:
測試一級緩存【默認是開啟的本地緩存的】:

技術分享
@Test
            public void testGetEmployee(){
                EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
                
                Employee emp = mapper.getEmployeeById(2);
                System.out.println(emp);
                Employee emp2 = mapper.getEmployeeById(2);
                System.out.println(emp2);
                
                System.out.println(emp 
== emp2); }
View Code

一級緩存失效的情況【4種】(沒有使用到當前一級緩存的情況,效果就是,還需要再向數據庫發出查詢);
1.sqlSession不同。

技術分享
@Test
public void testGetEmployee() throws IOException{
    SqlSessionFactory sessionFactory = testBefore();
    SqlSession openSession= sessionFactory.openSession();
    EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class
); Employee emp = mapper.getEmployeeById(2); System.out.println(emp); SqlSession openSession2= sessionFactory.openSession(); EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class); Employee emp2 = mapper2.getEmployeeById(2); System.out.println(emp2); System.out.println(emp == emp2); openSession.close(); openSession2.close(); }
View Code

2.SqlSession相同,但是查詢條件不一樣[當前緩存中還沒有這個數據]

技術分享
@Test
                public void testGetEmployee() throws IOException{
                    SqlSessionFactory sessionFactory = testBefore();
                    SqlSession openSession= sessionFactory.openSession();
                    EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
                    Employee emp = mapper.getEmployeeById(2);
                    System.out.println(emp);

                    Employee emp2 = mapper.getEmployeeById(3);
                    System.out.println(emp2);    
                    System.out.println(emp == emp2);
                    openSession.close();
                }
View Code

3.SqlSession相同,但是兩次查詢之間執行了增刪改操作【這次增刪改可能對當前數據有影響】。

技術分享
@Test
                public void testGetEmployee() throws IOException{
                    SqlSessionFactory sessionFactory = testBefore();
                    SqlSession openSession= sessionFactory.openSession();
                    EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
                    Employee emp = mapper.getEmployeeById(2);
                    System.out.println(emp);
                    mapper.updateEmp(new Employee(1, 1, "張三豐","[email protected]", new Department(1)));
                    Employee emp2 = mapper.getEmployeeById(2);
                    System.out.println(emp2);    
                    System.out.println(emp == emp2);
                    openSession.close();
                }
View Code

4.SqlSession相同,手動清除了一級緩存[緩存清空]。

技術分享
@Test
                public void testGetEmployee() throws IOException{
                    SqlSessionFactory sessionFactory = testBefore();
                    SqlSession openSession= sessionFactory.openSession();
                    EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
                    Employee emp = mapper.getEmployeeById(2);
                    System.out.println(emp);
                    //手動清空緩存
                    openSession.clearCache();
                    Employee emp2 = mapper.getEmployeeById(2);
                    System.out.println(emp2);    
                    System.out.println(emp == emp2);
                    openSession.close();
                }
View Code

二級緩存:【全局緩存】:基於namespace級別的緩存:一個namespace對應一個二級緩存。
【一級緩存的範圍還是太小了,每次SqlSession一關閉,一級緩存中的數據就消失】
所以從這個角度講:能跨sqlSession的緩存為二級緩存!

工作機制:
1、一個會話,查詢一條數據,這個數據就會被放在當前會話的一級緩存中。
2.如果會話關閉,一級緩存中的數據會被保存到二級緩存中;新的會話查詢信息,就可以參照二級緩存中。
3.SqlSession === EmployeeMapper ===> Employee
DepartmentMapper ===> Department
不同namespace查出的數據會放在自己對應的緩存中(map)
效果:數據會從二級緩存中獲取
查出的數據都會被默認先放在一級緩存中。
只有會話提交或者關閉之後,一級緩存中的數據才會轉移到二級緩存中。
需要註意的是:在哪個Mapper.xml文件中開啟了<cache>緩存標簽,哪個Mapper中就開啟了二級緩存。

使用:
1).開啟全局二級緩存配置:<setting name="cacheEnabled" value="true"/>
2).去mapper.xml中配置使用二級緩存:
<cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024" type=""></cache>
<!--
?eviction=“FIFO”:緩存回收策略:
?LRU –最近最少使用的:移除最長時間不被使用的對象。
?FIFO –先進先出:按對象進入緩存的順序來移除它們。
?SOFT –軟引用:移除基於垃圾回收器狀態和軟引用規則的對象。
?WEAK –弱引用:更積極地移除基於垃圾收集器狀態和弱引用規則的對象。
?默認的是LRU。
?flushInterval:緩存刷新間隔
?緩存多長時間清空一次,默認不清空,設置一個毫秒值。
?size:引用數目,正整數
?代表緩存最多可以存儲多少個對象,太大容易導致內存溢出
?readOnly:是否只讀,true/false
?true:只讀緩存;mybatis認為所有從緩存中獲取數據的操作都是只讀操作,不會修改數據。
mybatis為了加快獲取速度,直接就會將數據在緩存中的引用交給用戶。不安全,速度快。
?false:非只讀:mybatis覺得獲取的數據可能會被修改。
mybatis會利用序列化&反序列化的技術克隆一份。安全,速度慢。
?type:指定自定義緩存的全類名
實現cache接口即可!
-->
3).我們的POJO需要實現序列化接口[implements Serializable]

測試二級緩存【測試代碼】:

技術分享
@Test
                    public void testGetEmployee() throws IOException{
                        SqlSessionFactory sessionFactory = testBefore();
                        //開啟兩個會話
                        SqlSession openSession= sessionFactory.openSession();
                        SqlSession openSession2 = sessionFactory.openSession();
                        //利用兩個openSession對象獲取兩個mapper對象
                        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
                        EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);
                        //用第一個openSession獲取的mapper對象查詢2號員工信息
                        Employee emp = mapper.getEmployeeById(2);
                        System.out.println(emp);
                        //關閉第一個openSession對象
                        openSession.close();
                        //用第二個openSession獲取的mapper對象查詢2號員工信息
                        Employee emp2 = mapper2.getEmployeeById(2);
                        System.out.println(emp2);    
                        openSession2.close();
                        
                    }
                    
View Code

//可以看到只發送了一次SQL語句,第二次查詢時從二級緩存中拿到的數據,並沒有發送新的sql語句。
//需要註意的是:只有一級緩存中關閉的情況下,二級緩存才會被使用


需要註意的是:在哪個Mapper.xml文件中開啟了<cache>緩存標簽,哪個Mapper中就開啟了二級緩存。可用DepartmentMapper.xml驗證


和緩存有關的設置/屬性:
1)cacheEnabled="true": false:關閉緩存(二級緩存關閉)【一級緩存一直可用】
2)每個select標簽都有useCache="true";
false:不使用緩存(一級緩存依然使用,二級緩存不使用)
3)每個增刪改標簽都有一個flushCache="true":增刪改執行完成後就會清楚緩存【一級二級緩存都會被清空】
查詢標簽:flushCache = "false"
如果flushCache = true;每次查詢之前都會清空緩存,緩存是沒有被使用!

MyBatis-緩存機制