SpringCacheとEhCacheがキャッシュ管理を実現

1.Springキャッシュを知る

Spring Cacheは、Springが提供する一連のキャッシュソリューションです。キャッシュの実装自体は提供しませんが、さまざまなキャッシュソリューションを統合するために、統一されたインターフェイスとコードの仕様、構成、注釈などを提供するため、ユーザーはキャッシュの詳細を気にする必要がありません。

Springは、アプリケーションへのキャッシュの追加、メソッドへのキャッシュの適用、およびメソッドの実行前にキャッシュに使用可能なデータがあるかどうかのチェックを「透過的に」サポートします。これにより、メソッドの実行回数を減らし、応答速度を上げることができます。キャッシュのアプリケーションは「透過的」であり、呼び出し元に干渉を引き起こすことはありません。アノテーション@EnableCachingによってキャッシュのサポートが有効になっている限り、SpringBootはキャッシュの基本構成を自動的に処理します。

SpringCacheはメソッドに作用します。キャッシュメソッドが呼び出されると、メソッドパラメータと戻り結果が「キー/値」(キー/値)としてキャッシュに保存され、同じパラメータでメソッドが呼び出された場合、メソッドは実行されなくなります。次回は、代わりに、キャッシュから直接結果を取得して返します。したがって、Spring Cacheを使用する場合は、キャッシュされたメソッドとメソッドパラメータが同じ場合に同じ結果が返されるようにする必要があります。

SpringBootによって提供される宣言型キャッシュアノテーションは次のとおりです。

注釈 説明
@EnableCaching キャッシュをオンにします。
@Cacheable クラスとメソッドで使用して、クラスまたはメソッドの戻り値をキーと値のペアの形式でキャッシュできます。
@CachePut メソッドが呼び出され、結果がキャッシュされます。
@CacheEvict キャッシュを空にしてください。
@キャッシング 複数の注釈タグを組み合わせるために使用されます。

宣言型キャッシュアノテーションの詳細な使用:「Springはキャッシュを使用し、Ehcacheを統合します」

 

2.EhCacheについて知る

Spring Bootは、さまざまなキャッシュ製品をサポートしています。デフォルトでは単純なキャッシュが使用されますが、正式な環境で使用することはお勧めしません。Ehcacheなどのより強力なキャッシュを構成できます。

Ehcacheは、広く使用されているオープンソースのJava分散キャッシュであり、メモリとディスクストレージ、キャッシュローダー、キャッシュ拡張、キャッシュ例外処理、GZIPキャッシュ、サーブレットフィルター、RESTおよびSOAPAPIのサポートなどの機能を備えています。

 

3.SpringBootとMyBatis間の統合プロジェクトを作成します

【例】 SpringBootとMyBatisの統合プロジェクトを作成し、ユーザー情報の照会、追加、変更、削除の機能を実現します。また、Spring CacheとEhCacheを使用してキャッシュ管理を実現すると、実行結果は次のようになります。

3.1データテーブルを作成する

MySQLデータベースにユーザー情報テーブル(tb_user)を作成し、データを追加します。

-- 判断数据表是否存在,存在则删除
DROP TABLE IF EXISTS tb_user;
 
-- 创建“用户信息”数据表
CREATE TABLE IF NOT EXISTS tb_user
( 
	user_id INT AUTO_INCREMENT PRIMARY KEY COMMENT '用户编号',
	user_name VARCHAR(50) NOT NULL COMMENT '用户姓名',
	age INT DEFAULT(0) NOT NULL COMMENT '年龄',
	blog_url VARCHAR(50) NOT NULL COMMENT '博客地址',
	blog_remark VARCHAR(50) COMMENT '博客信息'
) COMMENT = '用户信息表';
 
-- 添加数据
INSERT INTO tb_user(user_name,age,blog_url,blog_remark) VALUES('pan_junbiao的博客',32,'https://blog.csdn.net/pan_junbiao','您好,欢迎访问 pan_junbiao的博客');

3.2プロジェクトを作成する 

(1)SpringBootプロジェクトを作成します。プロジェクトの構造は次のとおりです。

(2)pom.xml構成情報を追加します

MyBatis、MySQL JDBCデータベースドライバー、Spring Bootキャッシュサポートスターター、Ehcacheキャッシュなどをpom.xml構成ファイルに追加します。

<!-- MyBatis与SpringBoot整合依赖 -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.3</version>
</dependency>

<!-- MySQL的JDBC数据库驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.20</version>
</dependency>

<!-- 引入Thymeleaf模板引擎 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<!-- Spring Boot缓存支持启动器 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
    <version>2.3.2.RELEASE</version>
</dependency>

<!-- Ehcache缓存管理器 -->
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
</dependency>

(3)構成関連情報

デフォルトのapplication.propertiesファイルのサフィックスを「.yml」に変更します。つまり、構成ファイル名はapplication.ymlであり、次の情報を構成します。

#Spring配置
spring:
  #缓存管理器
  cache:
    type: ehcache
    ehcache:
      config: classpath:ehcache.xml #缓存加载配置文件
  #使用Thymeleaf模板引擎
  thymeleaf:
    mode: HTML5
    encoding: UTF-8
    cache: false  #使用Thymeleaf模板引擎,关闭缓存
    servlet:
      content-type: text/html
  #DataSource数据源
  datasource:
    url: jdbc:mysql://localhost:3306/db_admin?useSSL=false&amp
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

#MyBatis配置
mybatis:
  type-aliases-package: com.pjb.entity #别名定义
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #指定 MyBatis 所用日志的具体实现,未指定时将自动查找
    map-underscore-to-camel-case: true #开启自动驼峰命名规则(camel case)映射
    lazy-loading-enabled: true #开启延时加载开关
    aggressive-lazy-loading: false #将积极加载改为消极加载(即按需加载),默认值就是false
    #lazy-load-trigger-methods: "" #阻挡不相干的操作触发,实现懒加载
    cache-enabled: true #打开全局缓存开关(二级环境),默认值就是true

 

4.EhCacheキャッシュマネージャーを構成します

4.1ehcache.xml構成ファイルを作成します

リソース(リソースディレクトリ)の下に、ehcache.xml構成ファイルを作成します。構成情報は次のとおりです。

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">

    <!-- 这个是磁盘存储路径,当内存缓存满了的时候,就会往这里面放,
      java.io.tmdir是操作系统缓存的临时目录,不同操作系统缓存目录不一样 -->
    <diskStore path="java.io.tmpdir"/>

    <!--defaultCache:echcache的默认缓存策略  -->
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            maxElementsOnDisk="10000000"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap"/>
    </defaultCache>
    <cache name="userCache"
           maxElementsInMemory="10000"
           eternal="false"
           timeToIdleSeconds="120"
           timeToLiveSeconds="120"
           maxElementsOnDisk="10000000"
           diskExpiryThreadIntervalSeconds="120"
           memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap"/>
    </cache>
</ehcache>

構成属性の説明: 

属性 説明
<diskStore path = "java.io.tmpdir" /> これはディスクストレージパスです。メモリキャッシュがいっぱいになると、そこに配置されます。java.io.tmdirは、オペレーティングシステムキャッシュの一時ディレクトリです。オペレーティングシステムごとにキャッシュディレクトリが異なります。
maxElementsInMemory メモリキャッシュに格納できる要素の最大数。キャッシュに配置された要素がこの値を超える場合、次の2つの状況があります。
(1)overflowToDisk = trueの場合、キャッシュ内の追加の要素は次の場所に配置されます。ディスクファイル。
(2)overflowToDisk = falseの場合、memoryStoreEvictionPolicy戦略に従ってキャッシュ内の元の要素を置き換えます。
オーバーフローToDisk メモリが不足しているときにディスクキャッシュを有効にするかどうか。
永遠の キャッシュ内のオブジェクトが永続的に有効かどうか。
timeToIdleSeconds 無効化前のキャッシュデータの許容アイドル時間(単位:秒)。eternal= falseの場合にのみ使用されます。デフォルト値は0で、アイドル時間が無限であることを意味します。キャッシュ内の要素がこの時間より長くアクセスされていない場合の場合、この要素はキャッシュからクリアされます。
timeToLiveSeconds キャッシュされたデータの合計存続時間(単位:秒)。eternal= falseの場合にのみ使用され、作成から開始して無効化で終了します。
maxElementsOnDisk ディスクキャッシュに保存できる要素の最大数。0は無限大を意味します。
diskExpiryThreadIntervalSeconds ディスクキャッシュクリーニングスレッドの実行間隔は、デフォルトで120秒です。
memoryStoreEvictionPolicy メモリの保存と解放の戦略、つまりmaxElementsInMemoryの制限に達すると、Ehcacheは指定された戦略に従ってメモリをクリーンアップします。LRU(最近使用されていない)、LFU(最も一般的に使用されている)、FIFO(最も一般的に使用されている)の3つの戦略があります。先入先出)。
defaultCache デフォルトのキャッシュ方法。
キャッシュ カスタムキャッシュ方式、自分で名前を設定します。

4.2キャッシュマネージャーの構成

Ehcache、Generic、Redis、Jcacheなどをサポートするようにapplication.yml構成ファイルでターゲットキャッシュマネージャーを構成します。この構成はEhcacheを使用します。

#Spring配置
spring:
  #缓存管理器
  cache:
    type: ehcache
    ehcache:
      config: classpath:ehcache.xml #缓存加载配置文件

4.3キャッシュ機能をオンにする

SpringBootプロジェクトのスタートアップエントリクラスにアノテーション@EnableCachingを追加して、キャッシュ機能を有効にします。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@SpringBootApplication
@EnableCaching
public class SpringcacheDemoApplication
{
    public static void main(String[] args)
    {
        SpringApplication.run(SpringcacheDemoApplication.class, args);
    }
}

 

5.EhCacheを使用してキャッシュ管理を実装します

5.1エンティティクラスの作成(エンティティレイヤー)

com.pjb.entityパッケージで、UserInfoクラス(ユーザー情報エンティティクラス)を作成します。

package com.pjb.entity;

import java.io.Serializable;

/**
 * 用户信息实体类
 * @author pan_junbiao
 **/
public class UserInfo implements Serializable
{
    private int userId; //用户编号
    private String userName; //用户姓名
    private int age; //年龄
    private String blogUrl; //博客地址
    private String blogRemark; //博客信息

    //省略getter与setter方法...
}

注:エンティティークラスはSerializableインターフェースを実装する必要があります。そうしないと、キャッシュ機能を実装できません。

5.2データベースマッピングレイヤー(マッパーレイヤー)

com.pjb.mapperパッケージで、UserMapperインターフェイス(ユーザー情報Mapper動的プロキシインターフェイス)を作成します。

package com.pjb.mapper;

import com.pjb.entity.UserInfo;
import org.apache.ibatis.annotations.*;
import org.springframework.stereotype.Repository;

/**
 * 用户信息Mapper动态代理接口
 * @author pan_junbiao
 **/
@Mapper
@Repository
public interface UserMapper
{
    /**
     * 根据用户ID,获取用户信息
     */
    @Select("SELECT * FROM tb_user WHERE user_id = #{userId}")
    public UserInfo getUserById(int userId);

    /**
     * 新增用户,并获取自增主键
     */
    @Insert("INSERT INTO tb_user(user_name,age,blog_url,blog_remark) VALUES(#{userName},#{age},#{blogUrl},#{blogRemark});")
    @Options(useGeneratedKeys = true, keyColumn = "user_id", keyProperty = "userId")
    public int insertUser(UserInfo userInfo);

    /**
     * 修改用户
     */
    @Update("UPDATE tb_user SET user_name = #{userName} ,age = #{age} ,blog_url = #{blogUrl} ,blog_remark = #{blogRemark} WHERE user_id = #{userId}")
    public int updateUser(UserInfo userInfo);

    /**
     * 删除用户
     */
    @Delete("DELETE FROM tb_user WHERE user_id = #{userId}")
    public int deleteUser(int userId);
}

5.3ビジネスロジック層(サービス層)

com.pjb.serviceパッケージの下にUserServiceインターフェイス(ユーザー情報ビジネスロジックインターフェイス)を作成します。

package com.pjb.service;

import com.pjb.entity.UserInfo;

/**
 * 用户信息业务逻辑接口
 * @author pan_junbiao
 **/
public interface UserService
{
    /**
     * 根据用户ID,获取用户信息
     */
    public UserInfo getUserById(int userId);

    /**
     * 新增用户,并获取自增主键
     */
    public UserInfo insertUser(UserInfo userInfo);

    /**
     * 修改用户
     */
    public UserInfo updateUser(UserInfo userInfo);

    /**
     * 删除用户
     */
    public int deleteUser(int userId);
}

com.pjb.service.implパッケージの下に、UserServiceImplクラス(ユーザー情報ビジネスロジッククラス)を作成します。

package com.pjb.service.impl;

import com.pjb.entity.UserInfo;
import com.pjb.mapper.UserMapper;
import com.pjb.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

/**
 * 用户信息业务逻辑类
 * @author pan_junbiao
 **/
//注意:必须对应配置文件ehcache.xml中cache节点的name属性值
//@CacheConfig(cacheNames = "userCache")
@Service
public class UserServiceImpl implements UserService
{
    @Autowired
    private UserMapper userMapper;

    //注意:必须对应配置文件ehcache.xml中cache节点的name属性值
    private static final String CACHE_NAME = "userCache";

    /**
     * 根据用户ID,获取用户信息
     */
    @Override
    @Cacheable(value = CACHE_NAME, key = "#userId")
    public UserInfo getUserById(int userId)
    {
        return userMapper.getUserById(userId);
    }

    /**
     * 新增用户,并获取自增主键
     */
    @Override
    @CachePut(value = CACHE_NAME, key = "#userInfo.userId")
    public UserInfo insertUser(UserInfo userInfo)
    {
        userMapper.insertUser(userInfo);
        return userInfo;
    }

    /**
     * 修改用户
     */
    @Override
    @CachePut(value = CACHE_NAME, key = "#userInfo.userId")
    public UserInfo updateUser(UserInfo userInfo)
    {
        userMapper.updateUser(userInfo);
        return userInfo;
    }

    /**
     * 删除用户
     */
    @Override
    @CacheEvict(value = CACHE_NAME, key = "#userId")
    public int deleteUser(int userId)
    {
        return userMapper.deleteUser(userId);
    }
}

上記のコードからわかるように、ユーザーにクエリを実行する方法では、@ Cacheableアノテーションを使用してキャッシュを有効にします。メソッドの追加と変更では、@ CachePutアノテーションを使用します。このアノテーションは、最初にメソッドを処理してから、結果をキャッシュします。データを削除するには、@ CacheEvictアノテーションを使用してキャッシュをクリアする必要があります。

@CacheConfigアノテーション:すべての@Cacheable()にvalue = "xxx"属性がある場合、メソッドが他にもあると書くのは明らかに面倒です。一度にすべて宣言できれば、問題を回避できるので、With @があります。 CacheConfigこの構成、@ CacheConfigは、キャッシュ名を共有できるようにするクラスレベルのアノテーションです。メソッドに別の名前を書き込むと、メソッド名が優先されます。

5.4コントローラーメソッド(コントローラーレイヤー)

com.pjb.controllerパッケージで、UserControllerクラス(ユーザーコントローラー)を作成して、ユーザーデータのクエリ、追加、変更、削除を実現し、データの戻りを実現します。

package com.pjb.controller;

import com.pjb.entity.UserInfo;
import com.pjb.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

/**
 * 用户信息控制器
 * @author pan_junbiao
 **/
@Controller
@RequestMapping("/user")
public class UserController
{
    @Autowired
    private UserService userService;

    /**
     * 获取用户信息
     */
    @RequestMapping("getUserById")
    public ModelAndView getUserById(int userId)
    {
        //根据用户ID,获取用户信息
        UserInfo userInfo = userService.getUserById(userId);

        if(userInfo==null)
        {
            userInfo = new UserInfo();
        }

        //返回结果
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("userInfo",userInfo);
        modelAndView.setViewName("/user-info.html");
        return modelAndView;
    }

    /**
     * 新增用户
     */
    @ResponseBody
    @RequestMapping("insertUser")
    public boolean insertUser()
    {
        //创建新用户
        UserInfo userInfo = new UserInfo();
        userInfo.setUserName("pan_junbiao的博客");
        userInfo.setAge(32);
        userInfo.setBlogUrl("https://blog.csdn.net/pan_junbiao");
        userInfo.setBlogRemark("您好,欢迎访问 pan_junbiao的博客");

        //执行新增方法
        userService.insertUser(userInfo);

        //返回结果
        return userInfo.getUserId() > 0 ? true : false;
    }

    /**
     * 修改用户
     */
    @ResponseBody
    @RequestMapping("updateUser")
    public boolean updateUser(int userId)
    {
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(userId);
        userInfo.setUserName("pan_junbiao的博客_02");
        userInfo.setAge(35);
        userInfo.setBlogUrl("https://blog.csdn.net/pan_junbiao");
        userInfo.setBlogRemark("您好,欢迎访问 pan_junbiao的博客");

        //执行修改方法
        userService.updateUser(userInfo);

        //返回结果
        return true;
    }

    /**
     * 删除用户
     */
    @ResponseBody
    @RequestMapping("deleteUser")
    public boolean deleteUser(int userId)
    {
        //执行新增方法
        int result = userService.deleteUser(userId);

        //返回结果
        return result > 0 ? true : false;
    }
}

5.5表示ページ(ビューレイヤー)

resources / templatesディレクトリの下にuser-info.htmlユーザー情報表示ページを作成します。

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>用户信息</title>
    <meta name="author" content="pan_junbiao的博客">
    <style>
        table { border-collapse: collapse; margin-bottom: 10px}
        table,table tr th, table tr td { border:1px solid #000000; padding: 5px 10px;}
    </style>
</head>
<body>

<div align="center">
    <table>
        <caption>用户信息</caption>
        <tr>
            <th>用户ID:</th>
            <td th:text="${userInfo.userId}"></td>
        </tr>
        <tr>
            <th>用户名称:</th>
            <td th:text="${userInfo.userName}"></td>
        </tr>
        <tr>
            <th>年龄:</th>
            <td th:text="${userInfo.age}"></td>
        </tr>
        <tr>
            <th>博客地址:</th>
            <td th:text="${userInfo.blogUrl}"></td>
        </tr>
        <tr>
            <th>备注信息:</th>
            <td th:text="${userInfo.blogRemark}"></td>
        </tr>
    </table>
</div>
</body>
</html>

これまでのところ、プロジェクトは作成されており、実行結果は次のとおりです。

次に、プロジェクトの他のメソッドを実行し、クエリメソッドのURLに複数回アクセスして、キャッシュ効果を体験します。主な観察結果は、データベースが操作されているかどうかです。データベースに操作データがなく、データが正常に返される場合は、キャッシュが成功していることを意味します。

 

おすすめ

転載: blog.csdn.net/pan_junbiao/article/details/107999734