1. 程式人生 > 其它 >Mapreduce例項——Map端join

Mapreduce例項——Map端join

Mybatis

13、快取

13.1、簡介

  • 什麼是快取[Cache]?

    • 存在記憶體中的臨時資料。
    • 將使用者經常查詢的資料放在快取(記憶體)中,使用者去查詢資料就不用從磁碟上(關係型資料庫資料檔案)查詢,從快取中查詢,從而提高查詢效率,解決了高併發系統的效能問題。
  • 為什 麼使用快取?

    • 減少和資料庫的互動次數,減少系統開銷,提高系統效率。
  • 什麼樣的資料能使用快取?

    • 經常查詢並且不經常改變的資料。
  • 查詢:連線資料庫,耗資源!

    • 一次查詢的結果,給他暫存在一個可以直接取到的地方!-->記憶體:快取

    • 我們再次查詢相同資料的時候,直接走快取,就不用走資料庫了。

13.2、Mybatis快取

  • Mybatis包含一個非常強大的查詢快取特性,它可以非常方便地定製和配置快取。快取可以極大的提升查詢效率。

  • Mybatis系統中預設定義了兩級快取:一級快取和二級快取。

    • 預設情況下,只有一級快取開啟。(SqlSession級別的快取,也稱為本地快取)
    • 二級快取需要手動開啟和配置,它是基於namespace級別的快取。
    • 為了提高擴充套件性,Mybatis定義了快取介面Cache。我們可以通過實現Cache介面來自定義二級快取。
  • 可用的清除策略有:

    • LRU-最近最少使用:移除最長時間不被使用的物件。
    • FIFO-先進先出:按物件進入快取的順序來移除它們。
    • SOFT-軟引用:基於垃圾回收器狀態和軟引用規則移除物件。
    • WEAK-弱引用:更積極地基於垃圾收集器狀態和弱引用規則移除物件。
    • 預設的清除策略是LRU。

13.3、一級快取

  • 一級快取也叫本地快取:SqlSession 。

    • 與資料庫同一次會話期間查詢到的資料會放在本地快取中。
    • 以後如果需要獲取相同的資料,直接從快取中拿,沒必要再去查詢資料庫。
  • 測試步驟:

    • 開啟日誌。

    • 測試在一個Sesion中查詢兩次相同記錄。

    • 檢視日誌輸出。

    • Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1ee807c6]
      ==>  Preparing: select * from user where id=? 
      ==> Parameters: 1(Integer)
      <==    Columns: id, name, pwd
      <==        Row: 1, admin, ADMIN
      <==      Total: 1
      User(id=1, name=admin, pwd=ADMIN)
      =================================
      User(id=1, name=admin, pwd=ADMIN)
      Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1ee807c6]
      Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@1ee807c6]
      Returned connection 518522822 to pool.
      
      
    •  @Test
          public void testSelectById(){
              SqlSession sqlSession = MybatisUtils.getSqlSession();
              UserMapper mapper = sqlSession.getMapper(UserMapper.class);
              User user = mapper.selectById(1);
              System.out.println(user);
              System.out.println("=================================");
              User user1= mapper.selectById(1);
              System.out.println(user1);
              sqlSession.close();
          }
      
  • 快取失效的情況:

    • 查詢不同的東西。

    • 增刪改操作,可能會改變原來的資料,所以必定會重新整理快取!

      • Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1ee807c6]
        ==>  Preparing: select * from user where id=? 
        ==> Parameters: 1(Integer)
        <==    Columns: id, name, pwd
        <==        Row: 1, admin, ADMIN
        <==      Total: 1
        User(id=1, name=admin, pwd=ADMIN)
        =================================
        ==>  Preparing: update user set name=?,pwd=? where id=? 
        ==> Parameters: 5(String), 5(String), 4(Integer)
        <==    Updates: 1
        Committing JDBC Connection [com.mysql.jdbc.JDBC4Connection@1ee807c6]
        =================================
        ==>  Preparing: select * from user where id=? 
        ==> Parameters: 1(Integer)
        <==    Columns: id, name, pwd
        <==        Row: 1, admin, ADMIN
        <==      Total: 1
        User(id=1, name=admin, pwd=ADMIN)
        Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1ee807c6]
        Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@1ee807c6]
        Returned connection 518522822 to pool.
        
      •  @Test
            public void testSelectById(){
                SqlSession sqlSession = MybatisUtils.getSqlSession();
                UserMapper mapper = sqlSession.getMapper(UserMapper.class);
                User user = mapper.selectById(1);
                System.out.println(user);
                  System.out.println("=================================");
                int i = mapper.updateUser(new User(4, "5", "5"));
                //提交事務
                sqlSession.commit();
                System.out.println("=================================");
                User user1= mapper.selectById(1);
                System.out.println(user1);
                sqlSession.close();
            }
        
    • 查詢不同的Mapper.xml。

    • 手動清理快取!

      •   sqlSession.clearCache();//手動清理快取
        
  • 小結:一級快取預設是開啟的,只在一次SqlSession中有效,也就是拿到連線到關閉連線這個區間段!

  • 一級快取就是一個Map。

13.4、二級快取

  • 預設情況下,只啟用了本地的會話快取。

  • 二級快取也叫全域性快取,一級快取作用域太低了,所以誕生了二級快取。

  • 基於namespace級別的快取,一個名稱空間,對應一個二級快取。

  • 工作機制

    • 一個會話查詢一條資料,這個資料就會被放在當前會話的一級快取中。
    • 如果當前會話關閉了,這個會話對應的一級快取就沒了;但是我們想要的是,會話關閉了,一級快取中的資料被儲存到二級快取中。
    • 新的會話查詢資訊,就可以從二級快取中獲取內容。
    • 不同的mapper查出的資料會放在自己對應的快取(map)中。
  • 步驟:

    • 開啟全域性快取

      • <!--顯示的開啟全域性快取-->
        <setting name="cacheEnabled" value="true"></setting>
        
    • 在要使用二級快取的Mapper中開啟

      • <!--在當前Mapper.xml中使用二級快取-->
            <cache></cache>
        
      • 也可以自定義引數

        • <!--在當前Mapper.xml中使用二級快取-->
              <cache eviction="FIFO"
                     flushInterval="60000"
                     size="512"
                     readOnly="true"></cache> 
          
        • <!--調優-->
          <select useCache="flase"  flushCache="true"></select>
          <!--使用快取   重新整理快取-->
          
  • 問題:我們需要將實體類序列化!否則就會報錯!

    • caused by:java.io.NotserializableException:com.jcooling.pojo.user
      
    • public class User implements Serializable {
          private int id;
          private String name;
          private String pwd;
      }
      
  • 測試

    •  @Test
          public void test(){
              SqlSession sqlSession = MybatisUtils.getSqlSession();
              SqlSession sqlSession1 = MybatisUtils.getSqlSession();
              UserMapper mapper = sqlSession.getMapper(UserMapper.class);
              User user = mapper.selectById(1);
              System.out.println(user);
              sqlSession.close();
              System.out.println("=================================");
              UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
              User user1= mapper1.selectById(1);
              System.out.println(user1);
              System.out.println(user==user1);
              sqlSession1.close();
          }
      
  • 小結:

    • 只要開啟了二級快取,在同一個Mapper下就有效。
    • 所有的資料都會先放在一級快取中。
    • 只有當會話提交,或者關閉的時候,才會提交到二級緩衝中。

13.5、快取原理

  • 快取順序
    • 先看二級快取中有沒有。
    • 再看一級快取中有沒有。
    • 查詢資料庫。

13.6、自定義快取ehcache

  • Ehcache是一種廣泛使用的開源Java分散式快取。主要面向通用快取。

  • 要在程式中使用ehcache,先要導包!

    • <!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
          <dependency>
              <groupId>org.mybatis.caches</groupId>
              <artifactId>mybatis-ehcache</artifactId>
              <version>1.1.0</version>
          </dependency>
      
  • 在mapper中指定使用我們的ehcache快取實現!

    • <cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
      
  • ehcache.xml

    • <?xml version="1.0" encoding="UTF-8"?>
      <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
               updateCheck="false">
          <!--
             diskStore:為快取路徑,ehcache分為記憶體和磁碟兩級,此屬性定義磁碟的快取位置。引數解釋如下:
             user.home – 使用者主目錄
             user.dir  – 使用者當前工作目錄
             java.io.tmpdir – 預設臨時檔案路徑
           -->
          <diskStore path="java.io.tmpdir/Tmp_EhCache"/>
          <!--
            defaultCache:預設快取策略,當ehcache找不到定義的快取時,則使用這個快取策略。只能定義一個。
           -->
          <!--
            name:快取名稱。
            maxElementsInMemory:快取最大數目
            maxElementsOnDisk:硬碟最大快取個數。
            eternal:物件是否永久有效,一但設定了,timeout將不起作用。
            overflowToDisk:是否儲存到磁碟,當系統當機時
            timeToIdleSeconds:設定物件在失效前的允許閒置時間(單位:秒)。僅當eternal=false物件不是永久有效時使用,可選屬性,預設值是0,也就是可閒置時間無窮大。
            timeToLiveSeconds:設定物件在失效前允許存活時間(單位:秒)。最大時間介於建立時間和失效時間之間。僅當eternal=false物件不是永久有效時使用,預設是0.,也就是物件存活時間無窮大。
            diskPersistent:是否快取虛擬機器重啟期資料 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
            diskSpoolBufferSizeMB:這個引數設定DiskStore(磁碟快取)的快取區大小。預設是30MB。每個Cache都應該有自己的一個緩衝區。
            diskExpiryThreadIntervalSeconds:磁碟失效執行緒執行時間間隔,預設是120秒。
            memoryStoreEvictionPolicy:當達到maxElementsInMemory限制時,Ehcache將會根據指定的策略去清理記憶體。預設策略是LRU(最近最少使用)。你可以設定為FIFO(先進先出)或是LFU(較少使用)。
            clearOnFlush:記憶體數量最大時是否清除。
            memoryStoreEvictionPolicy:可選策略有:LRU(最近最少使用,預設策略)、FIFO(先進先出)、LFU(最少訪問次數)。
            FIFO,first in first out,這個是大家最熟的,先進先出。
            LFU, Less Frequently Used,就是上面例子中使用的策略,直白一點就是講一直以來最少被使用的。如上面所講,快取的元素有一個hit屬性,hit值最小的將會被清出快取。
            LRU,Least Recently Used,最近最少使用的,快取的元素有一個時間戳,當快取容量滿了,而又需要騰出地方來快取新的元素的時候,那麼現有快取元素中時間戳離當前時間最遠的元素將被清出快取。
         -->
          <defaultCache
                  eternal="false"
                  maxElementsInMemory="10000"
                  overflowToDisk="false"
                  diskPersistent="false"
                  timeToIdleSeconds="1800"
                  timeToLiveSeconds="259200"
                  memoryStoreEvictionPolicy="LRU"/>
          <cache
                  name="cloud_user"
                  eternal="false"
                  maxElementsInMemory="5000"
                  overflowToDisk="false"
                  diskPersistent="false"
                  timeToIdleSeconds="1800"
                  timeToLiveSeconds="1800"
                  memoryStoreEvictionPolicy="LRU"/>
      </ehcache>
      
    • public class MyCache implements Cache {}//自定義