Mybatisのプライマリキャッシュとセカンダリキャッシュの原理と使用、セカンダリキャッシュとキャッシュの更新の指定された方法の禁止、EhcacheのMybatis統合、セカンダリキャッシュの使用シナリオと制限-day03

最初のセクションMybatisキャッシュ

1.1Mybatisキャッシュの理解

  • Mybatisのキャッシュは、第1レベルのキャッシュと第2レベルのキャッシュを含め、休止状態のキャッシュに似ています。第1レベルのキャッシュはデフォルトで使用され、第2レベルのキャッシュは手動でオンにする必要があります。
  • 第1レベルのキャッシュはsqlsessionを参照します。sqlsessionにはマップ構造であるデータ領域があります。この領域は第1レベルのキャッシュ領域です。第1レベルのキャッシュのキーは、SQLステートメント、条件、ステートメントなどの情報で構成される一意の値です。第1レベルのキャッシュの値は、クエリの結果オブジェクトです。
  • 第2レベルのキャッシュは、同じ名前のマッパーを参照します。第2レベルのキャッシュには、マップ構造もあります。この領域は、第1レベルのキャッシュ領域です。
    ここに写真の説明を挿入

sqlSession1でデータを取得すると、SQLを使用せずにsqlSession2で同じデータを取得できます。このとき、セカンダリキャッシュを使用する必要があります。
セカンダリキャッシュはすべてのsqlSessionsで共有されます

1.2レベル1キャッシュ

原理

  • 最初のクエリでは、IDが1のユーザーがsqlを実行し、デフォルトで第1レベルのキャッシュが実行され、データが第1レベルのキャッシュマップに保存されます。ユーザーの変更、追加、削除が送信されると、第1レベルのキャッシュがクリアされます。 、IDが1で、sqlを再度実行する必要があるユーザーに再度クエリを実行します
    ここに写真の説明を挿入

使用とテスト

  • 以前のsaveおよびfindUserByIdメソッド
    ここに写真の説明を挿入
    ここに写真の説明を挿入
  • シリアル化インターフェイス(つまり、シリアル化可能なフラグ)を実装するように構成するクラスに注意してください。そうしないと、エラーが報告されます。
    ここに写真の説明を挿入

ここに写真の説明を挿入

	@Test
    public void test1() throws IOException {
    
    
        //1.读取配置文件
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //3.通过SqlSessionFactory创建SqlSession
        SqlSession sqlSession = sessionFactory.openSession();

        //默认情况下的一级缓存是开启的
        //4.通过会话获取dao接口
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

        User user1 = userMapper.findUserById(1);
        System.out.println(user1);

        //第二次不会执行sql
        User user2 = userMapper.findUserById(1);
        System.out.println(user2);

        sqlSession.close();
    }
  • 保存、更新、削除などが含まれる場合、第1レベルのキャッシュは自動的にクリアされます
    ここに写真の説明を挿入
	@Test
    public void test2() throws IOException {
    
    
        //1.读取配置文件
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //3.通过SqlSessionFactory创建SqlSession
        SqlSession sqlSession = sessionFactory.openSession();

        //默认情况下的一级缓存是开启的
        //保存、删除、更新后,一级缓存会自动清空,下次查询会再次执行sql
        //4.通过会话获取dao接口
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

        User user1 = userMapper.findUserById(1);
        System.out.println(user1);

        //保存一个新用户
        userMapper.save(new User("shu1","男",new Date(),"北京市"));
        //若要保存到数据库记得提交事务,否则不影响数据库,这里只做演示一级缓存可不提交
        sqlSession.commit();
        //此时第二次会执行sql
        User user2 = userMapper.findUserById(1);
        System.out.println(user2);

        sqlSession.close();
    }

ここに写真の説明を挿入

1.3セカンダリキャッシュ

原理

ここに写真の説明を挿入

使用とテスト

  1. (グローバル構成ファイルで構成された)セカンダリキャッシュの一般スイッチをオンにします(day01でより多くの設定が設定されます)
    ここに写真の説明を挿入
  2. UserMapper.xmlでセカンダリキャッシュを構成します
    ここに写真の説明を挿入
  3. テスト
  • シリアル化インターフェイス(つまり、シリアル化可能なフラグ)を実装するように構成するクラスに注意してください。そうしないと、エラーが報告されます。
    ここに写真の説明を挿入
    ここに写真の説明を挿入
	//二级缓存
    @Test
    public void test3() throws IOException {
    
    
        //1.读取配置文件
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //3.通过SqlSessionFactory创建SqlSession
        SqlSession sqlSession1 = sessionFactory.openSession();
        SqlSession sqlSession2 = sessionFactory.openSession();

        //默认情况下的一级缓存是开启的
        //保存、删除、更新后,一级缓存会自动清空,下次查询会再次执行sql
        //4.通过会话获取dao接口
        UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
        UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);


        User user1 = userMapper1.findUserById(1);
        System.out.println(user1);
        //session关闭了,数据才会写入二级缓存
        sqlSession1.close();

        User user2 = userMapper2.findUserById(1);
        System.out.println(user2);
        sqlSession2.close();
    }
  1. 挿入、更新、削除などの操作が実行されると、セカンダリキャッシュがクリアされます
	@Test
    public void test4() throws IOException {
    
    
        //1.读取配置文件
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //3.通过SqlSessionFactory创建SqlSession
        SqlSession sqlSession1 = sessionFactory.openSession();
        SqlSession sqlSession2 = sessionFactory.openSession();
        SqlSession sqlSession3 = sessionFactory.openSession();

        //默认情况下的一级缓存是开启的
        //保存、删除、更新后,一级缓存会自动清空,下次查询会再次执行sql
        //4.通过会话获取dao接口
        UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
        UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
        UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);

        User user1 = userMapper1.findUserById(1);
        System.out.println(user1);
        sqlSession1.close();

        //保存用户,二级缓存也会清空
        userMapper3.save(new User("shu2","男",new Date(),"上海市"));
        sqlSession3.commit();
        sqlSession3.close();

        User user2 = userMapper2.findUserById(1);
        System.out.println(user2);
        sqlSession2.close();

    }

ここに写真の説明を挿入
ここに写真の説明を挿入

指定されたメソッドの第2レベルのキャッシュを無効にします

ここに写真の説明を挿入

  • 指定されたメソッドの第2レベルのキャッシュは無効になり、このメソッドの第2レベルのキャッシュは有効にならず、他のメソッドは影響しません。
    ここに写真の説明を挿入

キャッシュを更新

  • 指定されたメソッドの第2レベルのキャッシュは、上記で無効になっています。このメソッドは、第2レベルのキャッシュを反映するために使用されます。無効を削除することを忘れないでください。そうしないと、キャッシュが更新されません。
    ここに写真の説明を挿入
    ここに写真の説明を挿入

総括する

第1レベルのキャッシュと第2レベルのキャッシュの共通点:挿入、更新、削除などの操作が実行されると、キャッシュはクリアされます。

1.4ehcacheを統合する

  • 質問:Mybatisに付属のキャッシュを使用せずに、ehcacheキャッシュを統合してみませんか?
  • 回答:Mybatis自体は永続層フレームワークであり、専用のキャッシングフレームワークではないため、キャッシングの実装は分散型キャッシングフレームワークをサポートするには不十分ですが、Ehcacheは分散型キャッシングフレームワークです。

配布されるもの

  • パフォーマンスを向上させるために、システムは通常、分散展開(クラスター展開)を採用します
    ここに写真の説明を挿入

統合された思考

  • キャッシュには標準化されたインターフェイスCacheがあり(使用したい場合は、実装して対応するメソッドを記述します)、デフォルトの実装はmybatisのPerpetualCacheです。mybatisのセカンダリキャッシュを統合する場合は、キャッシュインターフェイスを実装します。
    ここに写真の説明を挿入
  • Mybatisには実装キャッシュが付属しています
    ここに写真の説明を挿入

統合手順

ステップ1:jarパッケージをインポートします

ここに写真の説明を挿入
ここに写真の説明を挿入

  • ehcacheによって実装されたキャッシュを見ることができます
    ここに写真の説明を挿入

手順2:マッピングファイルでキャッシュタグを構成する

ここに写真の説明を挿入

	<!--配置缓存
    type不写,默认使用的就是mybatis自带的缓存技术,perpetualCache永久缓存
    -->
    <cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>

ステップ3:srcの下にehcache構成ファイルを追加します

ここに写真の説明を挿入

  • それをsrcディレクトリにコピーし、名前をehcache.xmlに変更します(コメントを削除した後)
    ここに写真の説明を挿入

  • maxElementsInMemory:メモリベースのキャッシュに保存できるオブジェクトの最大数を設定します。

  • eternal:オブジェクトが永続的であるかどうかを設定します。trueは期限切れにならないことを意味し、falseの場合は、timeToIdleSecondsとtimeToLiveSecondsに従って判断する必要があります。

  • timeToIdleSeconds:オブジェクトがアイドル状態になる最大時間を秒単位で設定します。この時間が経過すると、オブジェクトは期限切れになります。オブジェクトの有効期限が切れると、EHCacheはオブジェクトをキャッシュから削除します。この値が0の場合、オブジェクトが無期限にアイドル状態になる可能性があることを意味します。(単位は秒です)

  • timeToLiveSeconds:オブジェクトが存続する最長時間を設定します。この時間が経過すると、オブジェクトは期限切れになります。この値が0の場合、オブジェクトがキャッシュに無期限に存在する可能性があることを意味します。属性値は、timeToIdleSeconds属性値(秒単位)以上である必要があります

  • overlayToDisk:内部キャッシュ内のオブジェクトの数が上限に達した後にオーバーフローオブジェクトをハードディスクベースのキャッシュに書き込むかどうかを設定します

  • diskPersistent:jvmの終了時にオブジェクト(ハードディスクに保存されている)を永続化するかどうか。trueまたはfalseはオプションで、デフォルトはfalseです。

  • diskExpiryThreadIntervalSeconds:期限切れのオブジェクトのクリア専用のリスニングスレッドのポーリング時間を指定します。(単位は秒です)

  • memoryStoreEvictionPolicy:メモリキャッシュが最大に達し、新しい要素が追加されると、キャッシュ内の要素がディスクに削除されたときのポリシー。デフォルトはLRU(最近使用されていない)、オプションはLFU(使用頻度が最も低い、使用されていない)およびFIFO(ファーストインファーストアウト)です。

  • LRU(最近使用されていない):キャッシュされた要素にタイムスタンプがあります。キャッシュ容量がいっぱいで、新しい要素をキャッシュするためのスペースを確保する必要がある場合、タイムスタンプが現在の時刻から最も遠い既存のキャッシュ要素内の要素キャッシュからクリアされます。

  • LFU(あまり使用されない):キャッシュされた要素にはヒット属性があり、ヒット値が最も小さい要素がキャッシュからクリアされます。

ステップ4:テスト

  • 前のテストセカンダリキャッシュを使用します
	//二级缓存
    @Test
    public void test3() throws IOException {
    
    
        //1.读取配置文件
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //3.通过SqlSessionFactory创建SqlSession
        SqlSession sqlSession1 = sessionFactory.openSession();
        SqlSession sqlSession2 = sessionFactory.openSession();

        //默认情况下的一级缓存是开启的
        //保存、删除、更新后,一级缓存会自动清空,下次查询会再次执行sql
        //4.通过会话获取dao接口
        UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
        UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);

        User user1 = userMapper1.findUserById(1);
        System.out.println(user1);
        //session关闭了,数据才会写入二级缓存
        sqlSession1.close();

        User user2 = userMapper2.findUserById(1);
        System.out.println(user2);
        sqlSession2.close();
    }
  • SQLを1回実行し、2番目のレベルのキャッシュから2回目にフェッチします。
    ここに写真の説明を挿入

1.5セカンダリキャッシュの使用シナリオ

  • 高いアクセス応答速度を必要とするがリアルタイムパフォーマンスが低いクエリの場合、セカンダリキャッシュテクノロジーを使用できます
    注:第2レベルのキャッシュを使用する場合、第2レベルのキャッシュを定期的に更新するには、更新間隔(cacheタグにflashInterval属性があります)を設定する必要があります。この更新間隔は、30分、60分などの特定のニーズに応じて設定されます。ミリ秒です。
  • 例:キャッシュの更新間隔を60分に設定します(60分ごとにキャッシュをクリアします)
    ここに写真の説明を挿入

1.6第2レベルのキャッシュの制限

  • Mybatisの第2レベルのキャッシュは、きめ細かいデータには適切に実装されていません。

  • 例:製品情報のキャッシュ。製品情報クエリの訪問数が多いため、ユーザーは毎回最新の製品情報をクエリする必要があります。このとき、セカンダリキャッシュを使用すると、製品が変更されたときに製品のキャッシュ情報のみを更新することはできません。セカンダリキャッシュはマッパーレベルであるため、他の製品キャッシュ情報は更新されません。製品の情報が更新されると、すべての製品の情報キャッシュデータがクリアされます。

  • このような問題を解決するには、必要に応じてビジネスレイヤーでターゲットを絞った方法でデータをキャッシュする必要があります。

  • たとえば、頻繁に変更されるデータに対する操作は、別の名前名のマッパーに個別に配置できます。

おすすめ

転載: blog.csdn.net/qq_43414199/article/details/108883820