Skip Navigation
Show nav
Dev Center
  • Get Started
  • ドキュメント
  • Changelog
  • Search
  • Get Started
    • Node.js
    • Ruby on Rails
    • Ruby
    • Python
    • Java
    • PHP
    • Go
    • Scala
    • Clojure
    • .NET
  • ドキュメント
  • Changelog
  • More
    Additional Resources
    • Home
    • Elements
    • Products
    • Pricing
    • Careers
    • Help
    • Status
    • Events
    • Podcasts
    • Compliance Center
    Heroku Blog

    Visit the Heroku Blog

    Find news and updates from Heroku in the blog.

    Visit Blog
  • Log inorSign up
Hide categories

Categories

  • Heroku のアーキテクチャ
    • コンピューティング (dyno)
      • dyno の管理
      • dyno の概念
      • dyno の動作
      • dyno の参照資料
      • dyno のトラブルシューティング
    • スタック (オペレーティングシステムイメージ)
    • ネットワーキングと DNS
    • プラットフォームポリシー
    • プラットフォームの原則
  • 開発者ツール
    • コマンドライン
    • Heroku の VS Code 拡張機能
  • デプロイ
    • Git を使用したデプロイ
    • Docker によるデプロイ
    • デプロイ統合
  • 継続的デリバリーとインテグレーション
    • 継続的統合
  • 言語サポート
    • Node.js
      • Node.js アプリのトラブルシューティング
      • Heroku での Node.js の動作
      • Node.js の操作
    • Ruby
      • Rails のサポート
      • Bundler の使用
      • Ruby の操作
      • Heroku での Ruby の動作
      • Ruby アプリのトラブルシューティング
    • Python
      • Python の操作
      • Python でのバックグラウンドジョブ
      • Heroku での Python の動作
      • Django の使用
    • Java
      • Heroku での Java の動作
      • Java の操作
      • Maven の使用
      • Spring Boot の使用
      • Java アプリのトラブルシューティング
    • PHP
      • PHP の操作
      • Heroku での PHP の動作
    • Go
      • Go の依存関係管理
    • Scala
    • Clojure
    • .NET
      • Working with .NET
  • データベースとデータ管理
    • Heroku Postgres
      • Postgres の基礎
      • Postgres スターターガイド
      • Postgres のパフォーマンス
      • Postgres のデータ転送と保持
      • Postgres の可用性
      • Postgres の特別なトピック
      • Heroku Postgres への移行
    • Heroku Key-Value Store
    • Apache Kafka on Heroku
    • その他のデータストア
  • AI
    • Vector Database
    • Working with AI
    • Heroku Inference
      • AI Models
      • Inference Essentials
      • Quick Start Guides
      • Inference API
    • Model Context Protocol
  • モニタリングとメトリクス
    • ログ記録
  • アプリのパフォーマンス
  • アドオン
    • すべてのアドオン
  • 共同作業
  • セキュリティ
    • アプリのセキュリティ
    • ID と認証
      • シングルサインオン (SSO)
    • Private Space
      • インフラストラクチャネットワーキング
    • コンプライアンス
  • Heroku Enterprise
    • Enterprise Accounts
    • Enterprise Team
    • Heroku Connect (Salesforce 同期)
      • Heroku Connect の管理
      • Heroku Connect のリファレンス
      • Heroku Connect のトラブルシューティング
  • パターンとベストプラクティス
  • Heroku の拡張
    • Platform API
    • アプリの Webhook
    • Heroku Labs
    • アドオンのビルド
      • アドオン開発のタスク
      • アドオン API
      • アドオンのガイドラインと要件
    • CLI プラグインのビルド
    • 開発ビルドパック
    • Dev Center
  • アカウントと請求
  • トラブルシューティングとサポート
  • Salesforce とのインテグレーション
  • 言語サポート
  • Java
  • Spring Boot の使用
  • Memcache を使用した Spring Boot アプリケーションのスケーリング

This article was contributed by The MemCachier Add-on

MemCachier manages and scales clusters of memcache servers so you can focus on your app. Tell us how much memory you need and get started for free instantly. Add capacity later as you need it.

follow @MemCachier on Twitter

Memcache を使用した Spring Boot アプリケーションのスケーリング

日本語 — Switch to English

この記事の英語版に更新があります。ご覧の翻訳には含まれていない変更点があるかもしれません。

最終更新日 2022年03月24日(木)

Table of Contents

  • 前提条件
  • Heroku への Spring Boot アプリケーションのデプロイ
  • タスクリスト機能の追加
  • キャッシングを Spring Boot に追加する
  • 参考情報と資料

Memcache は、Web アプリとモバイルアプリバックエンドのパフォーマンスとスケーラビリティを改善する技術です。ページの読み込みが遅すぎる場合や、アプリにスケーラビリティの問題がある場合は、Memcache の使用を検討してください。小規模なサイトであっても、Memcache の導入によってページの読み込みを高速化し、将来の変化にアプリを対応させることができます。

このガイドでは、単純な Spring Boot 2​ アプリケーション (ベースは Spring Framework 5​ を作成して Heroku にデプロイし、Memcache を追加してパフォーマンスのボトルネックを軽減する方法を示します。

ソースコード​を表示したり、次の Heroku Button を使用してそれをデプロイしたりできます。

Heroku にデプロイ

前提条件

このガイドの手順を完了する前に、以下のすべての条件を満たしていることを確認してください。

  • Java の知識がある (Spring Boot の知識もあれば理想的です)
  • Heroku ユーザーアカウント (無料ですぐにサインアップ)
  • Maven と Heroku CLI​ がコンピュータにインストールされている

Heroku への Spring Boot アプリケーションのデプロイ

Spring Boot アプリケーションを簡単に作成するために、Spring Boot CLI​ をインストールすることをお勧めします。 CLI をインストールしない場合、Spring Initializer​ から Spring Boot スケルトンを設定およびダウンロードすることもできます。

spring という名前の Ruby on Rails アプリケーションもあります。このアプリケーションが インストールされているか、このバイナリを shim する Ruby バージョンマネージャー rbenv​ が インストールされている場合は、spring cli のエイリアスを作成します (例: alias springboot='/opt/spring-boot-cli/bin/spring'​)。

CLI を使用すると、スケルトンを簡単に作成できます。

$ spring init --d=web,data-jpa,thymeleaf -g com.memcachier -a tutorial -n TaskList memcached_tutorial
$ cd memcached_tutorial

作成されるスケルトンは、データベースをサポートし (data-jpa​)、thymeleaf​ テンプレート言語を使用する Web アプリです。JSP、groovy、freemaker、mustache など、その他のテンプレート言語も Spring Boot ではサポートされています。

Heroku アプリの作成

3 つの簡単な手順で、Spring Boot スケルトンから Heroku アプリを作成できます。

  1. アプリの起動方法を Heroku に指示するために、Procfile​ を追加する必要があります。
  $ echo 'web: java -Dserver.port=$PORT $JAVA_OPTS -jar target/*.jar' > Procfile
  1. Git リポジトリを初期化してスケルトンをコミットします。
  $ git init
  $ git add .
  $ git commit -m 'Spring Boot skeleton for Heroku'
  1. Heroku アプリを作成します。
  $ heroku create

このコマンドにより、実際の Heroku アプリケーションが作成されるのに加えて、対応するリモートがローカルの Git リポジトリに追加されます。

タスクリスト機能の追加

ユーザーがタスクを表示、追加、削除できるタスクリストをアプリに追加しましょう。そのためには、次の手順に従う必要があります。

  1. データベースをセットアップする
  2. Task​ エンティティと保存先のテーブルを作成する
  3. ビューとコントローラーロジックを作成する

PostgreSQL データベースのセットアップ

Spring Boot でデータベースを設定する前に、データベースを作成する必要があります。Heroku では、次のようにして、無料の開発用データベースをアプリに追加できます。

$ heroku addons:create heroku-postgresql:hobby-dev

アプリ用の PostgreSQL データベースが作成され、その URL を含む DATABASE_URL​ 環境設定が追加されます。

Spring Boot では、変数 SPRING_DATASOURCE_URL​ を設定する必要があります。この 変数には DATABASE_URL​ と同じ URL が含まれますが、 postgres​ ではなく jdbc:postgresql​ で始まる点が異なります。この変数の値は実行時に Heroku によって自動的に設定されるため、心配無用です。

このデータベースを使用するには、いくつかのパッケージをインストールする必要があります。次の依存関係を pom.xml​ に追加します。

<dependency>
  <groupId>org.postgresql</groupId>
  <artifactId>postgresql</artifactId>
</dependency>
<dependency>
  <groupId>javax.xml.bind</groupId>
  <artifactId>jaxb-api</artifactId>
  <version>2.3.0</version>
</dependency>
<dependency>
  <groupId>org.liquibase</groupId>
  <artifactId>liquibase-core</artifactId>
  <version>3.6.1</version>
</dependency>
  • 最初の依存関係は PostgreSQL ドライバーです。

  • Java SE の新しいバージョンには JAXB API が含まれなくなったため、2 番目の依存関係でこの API を追加します。詳細は、StackOverflow のこのスレッド​を参照してください。

  • 3 番目の依存関係は、liquibase データベース移行を作成および実行するためのものです。

ここで、src/main/resources/application.properties​ でデータベースを設定できます。

  spring.datasource.driverClassName=org.postgresql.Driver
  spring.datasource.maxActive=10
  spring.datasource.maxIdle=5
  spring.datasource.minIdle=2
  spring.datasource.initialSize=5
  spring.datasource.removeAbandoned=true

  # Supress exception regarding missing PostgreSQL CLOB feature at Spring startup.
  # See http://vkuzel.blogspot.ch/2016/03/spring-boot-jpa-hibernate-atomikos.html
  spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false
  spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL9Dialect

PostgreSQL データベースを使用する準備ができました。次のようにして変更内容を保存します。

$ git commit -am 'Database setup'

Heroku 上の Java からリレーショナルデータベースに接続する方法の詳細は、このガイド​を参照してください。

Task エンティティとデータベーステーブルの作成

タスクの作成と保存のために、3 つのものを作成する必要があります。Task​ エンティティ、タスクの保存および取得方法を Spring Boot に指示するリポジトリ、実際のテーブルをデータベースに作成する移行です。

  1. Task​ エンティティを src/main/java/com/memcachier/tutorial/Task.java​ に追加します。
  package com.memcachier.tutorial;

  import javax.persistence.Entity;
  import javax.persistence.GeneratedValue;
  import javax.persistence.GenerationType;
  import javax.persistence.Id;

  import org.hibernate.validator.constraints.NotEmpty;

  @Entity
  public class Task {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;
    @NotEmpty
    private String name;

    protected Task() {}

    public Task(String name) {
      this.name = name;
    }

    public Long getId() {
      return this.id;
    }

    public String getName() {
      return this.name;
    }

    public void setName(String name) {
      this.name = name;
    }

    @Override
    public String toString() {
      return String.format("Task[id=%d, name='%s']", this.id, this.name);
    }

  }
  1. リポジトリを src/main/java/com/memcachier/tutorial/TaskRepository.java​ に作成します。
  package com.memcachier.tutorial;

  import java.util.List;
  import org.springframework.data.repository.CrudRepository;

  public interface TaskRepository extends CrudRepository<Task, Long> {}

データにアクセスするために基本の CRUD 関数以外のものが必要な場合、代わりに PagingAndSortingRepository​ または JpaRepository​ を拡張することもできます。詳細は、StackOverflow のこのスレッド​を 参照してください。

  1. liquibase 移行を src/main/resources/db/changelog/db.changelog-master.yaml​ に作成します。
  databaseChangeLog:
    - changeSet:
        id: 1
        author: memcachier
        changes:
          - createTable:
              tableName: task
              columns:
                - column:
                    name: id
                    type: int
                    autoIncrement: true
                    constraints:
                      primaryKey: true
                      nullable: false
                - column:
                    name: name
                    type: varchar(255)
                    constraints:
                      nullable: false

db​ および changelog​ フォルダーを作成する必要があります。 この移行は、アプリケーションが起動すると自動的に実行されます。

ここまでの変更内容を保存しましょう。

$ git add .
$ git commit -m 'Task table setup'

タスクリストアプリケーションの作成

実際のアプリケーションを構成するのは、フロントエンドに表示されるビューと、バックエンドの機能を実装するコントローラーです。

  • コントローラーを src/main/java/com/memcachier/tutorial/TaskController.java​ に作成します。
  package com.memcachier.tutorial;

  import javax.validation.Valid;
  import java.lang.Iterable;

  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.stereotype.Controller;
  import org.springframework.ui.ModelMap;
  import org.springframework.validation.BindingResult;
  import org.springframework.web.bind.annotation.ModelAttribute;
  import org.springframework.web.bind.annotation.RequestMapping;
  import org.springframework.web.bind.annotation.RequestMethod;
  import org.springframework.web.bind.annotation.RequestParam;

  @Controller
  @RequestMapping("/")
  public class TaskController {

    private TaskRepository taskRepo;

    @Autowired
    public TaskController(TaskRepository repo) {
      this.taskRepo = repo;
    }

    @RequestMapping(method = RequestMethod.GET)
    public String showAllTasks(ModelMap model) {
      Iterable<Task> tasks = this.taskRepo.findAll();
      model.addAttribute("tasks", tasks);
      model.addAttribute("newTask", new Task());
      return "task";
    }

    @RequestMapping(method = RequestMethod.POST)
    public String newTask(ModelMap model,
                          @ModelAttribute("newTask") @Valid Task task,
                          BindingResult result) {
      if (!result.hasErrors()) {
        this.taskRepo.save(task);
      }
      return showAllTasks(model);
    }

    @RequestMapping(method = RequestMethod.DELETE)
    public String deleteTask(ModelMap model, @RequestParam("taskId") Long id) {
      this.taskRepo.deleteById(id);
      return showAllTasks(model);
    }
  }

このコントローラーには、すべてのタスクを GET​ して task​ ビューを描画する機能、後からデータベースに保存される新しいタスクを POST​ する機能、既存のタスクを DELETE​ する機能のすべてが含まれています。

  • ビューを src/main/resources/templates/task.html​ に作成します。
  <!DOCTYPE HTML>
  <html xmlns:th="http://www.thymeleaf.org">
    <head>
      <title>MemCachier Spring Boot Tutorial</title>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

      <!-- Fonts -->
      <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.4.0/css/font-awesome.min.css"
            rel='stylesheet' type='text/css' />

      <!-- Bootstrap CSS -->
      <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
            rel="stylesheet" />
    </head>

    <body>
      <div class="container">

        <!-- New Task Card -->
        <div class="card">
          <div class="card-body">
            <h5 class="card-title">New Task</h5>

            <form th:object="${newTask}" method="POST">
              <div class="form-group">
                <input type="text" class="form-control"
                       placeholder="Task Name" th:field="*{name}" />
              </div>
              <button type="submit" class="btn btn-default">
                <i class="fa fa-plus"></i> Add Task
              </button>
            </form>
          </div>
        </div>

        <!-- Current Tasks -->
        <div th:if="${not #lists.isEmpty(tasks)}">
          <div class="card">
            <div class="card-body">
              <h5 class="card-title">Current Tasks</h5>

              <table class="table table-striped">
                <tr th:each="task : ${tasks}">
                  <!-- Task Name -->
                  <td th:text="${task.name}" class="table-text"></td>
                  <!-- Delete Button -->
                  <td>
                    <form th:object="${deleteTask}" th:method="DELETE">
                      <input type="hidden" name="taskId" th:value="${task.id}">
                      <button type="submit" class="btn btn-danger">
                        <i class="fa fa-trash"></i> Delete
                      </button>
                    </form>
                  </td>
                </tr>
              </table>
            </div>
          </div>
        </div>
      </div>

      <!-- Bootstrap related JavaScript -->
      <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
      <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
    </body>
  </html>

ビューは基本的に、2 つのカードで構成されます。1 つのカードには、新しいタスクを作成するためのフォームが含まれます。もう 1 つのカードには、既存のタスクが入ったテーブルと、対応するタスクを削除するための削除ボタンが含まれます。

これまでの作業を確認し、タスクリストを Heroku にデプロイしましょう。

$ git add .
$ git commit -m 'Add task list view and controller'
$ git push heroku master
$ heroku open

タスクをいくつか追加して、アプリケーションをテストします。タスクリストが Heroku 上で動作するようになりました。ここまで完了したら、Memcache を使用してタスクリストのパフォーマンスを向上させる方法を学ぶことができます。

キャッシングを Spring Boot に追加する

Memcache はインメモリの分散キャッシュです。そのプライマリ API は、SET(key, value)​ と GET(key)​ の 2 つの操作で構成されます。 Memcache は、複数のサーバーに分散していますが、操作は一定の時間に実行されるハッシュマップ (または辞書) のようなものです。

Memcache の最も一般的な用途は、コストの高いデータベースクエリや HTML レンダリングをキャッシュし、これらの高コスト操作を繰り返す必要をなくすことです。

Memcache のセットアップ

Spring Boot で Memcache を使用するには、まず実際の Memcache キャッシュをプロビジョニングする必要があります。これは、MemCachier アドオン​から無料で簡単に入手できます。

$ heroku addons:create memcachier:dev

次に、適切な依存関係を設定する必要があります。simple-spring-memcached​ と XMemcached​ を使用して、Spring Boot 内で Memcache を使用します。simple-spring-memcached​ と SpyMemcached​ を使用することもできます。後者の方法については、MemCachier のドキュメント​を参照してください。

simple-spring-memcached​ を使用するには、次の内容を pom.xml​ に追加します。

<dependency>
  <groupId>com.google.code.simple-spring-memcached</groupId>
  <artifactId>xmemcached-provider</artifactId>
  <version>4.0.0</version>
</dependency>
<!-- Force XMemcached to version 2.4.3 simple-spring-memcached uses 2.4.0 -->
<dependency>
  <groupId>com.googlecode.xmemcached</groupId>
  <artifactId>xmemcached</artifactId>
  <version>2.4.3</version>
</dependency>

src/main/java/com/memcachier/tutorial/MemCachierConfig.java​ で、Spring 用に Memcache を設定できるようになりました。

package com.memcachier.tutorial;

import java.net.InetSocketAddress;
import java.util.List;
import java.util.Map;
import java.util.HashMap;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.google.code.ssm.CacheFactory;
import com.google.code.ssm.config.AbstractSSMConfiguration;
import com.google.code.ssm.config.DefaultAddressProvider;
import com.google.code.ssm.providers.xmemcached.XMemcachedConfiguration;
import com.google.code.ssm.providers.xmemcached.MemcacheClientFactoryImpl;
import net.rubyeye.xmemcached.auth.AuthInfo;
import net.rubyeye.xmemcached.utils.AddrUtil;

@Configuration
public class MemCachierConfig extends AbstractSSMConfiguration {

  @Bean
  @Override
  public CacheFactory defaultMemcachedClient() {
    String serverString = System.getenv("MEMCACHIER_SERVERS").replace(",", " ");
    List<InetSocketAddress> servers = AddrUtil.getAddresses(serverString);
    AuthInfo authInfo = AuthInfo.plain(System.getenv("MEMCACHIER_USERNAME"),
                                       System.getenv("MEMCACHIER_PASSWORD"));
    Map<InetSocketAddress, AuthInfo> authInfoMap =
      new HashMap<InetSocketAddress, AuthInfo>();
    for(InetSocketAddress server : servers) {
      authInfoMap.put(server, authInfo);
    }

    final XMemcachedConfiguration conf = new XMemcachedConfiguration();
    conf.setUseBinaryProtocol(true);
    conf.setAuthInfoMap(authInfoMap);

    final CacheFactory cf = new CacheFactory();
    cf.setCacheClientFactory(new MemcacheClientFactoryImpl());
    cf.setAddressProvider(new DefaultAddressProvider(serverString));
    cf.setConfiguration(conf);
    return cf;
  }
}

これによって simple-spring-memcached​ が設定され、そのキャッシングアノテーションを使用できるようになります。simple-spring-memcached​ で有効化できる組み込みのキャッシングアノテーションは Spring からも提供されています。しかし、このチュートリアルでは、アノテーションで提供された simple-spring-memcached​ を使用します。こちらの方が全体的に柔軟性が高く、Memcached を使用したキャッシュに適しているからです。ただし、Spring のアノテーションを使用しても、このチュートリアルの動作に問題はありません。Spring の組み込みキャッシングアノテーションを使用する場合は、MemCachier のドキュメント​を参照してください。

コストの高いデータベースクエリをキャッシュする

Memcache を使用して、コストの高いデータベースクエリをキャッシュすることはよくあります。この単純な例にはコストの高いクエリはありませんが、学習のために、すべてのタスクをデータベースから取得するのはコストの高い操作であると仮定します。

Task のクエリをキャッシュするために、キャッシングを実装するメソッドで TaskRepository​ を拡張します。Spring Boot でリポジトリを拡張するには、3 つの手順が必要です。

  1. TaskRepository​ に追加するメソッドを備えたインターフェースを src/main/java/com/memcachier/tutorial/CachedTaskRepository.java​ に構築します。
  package com.memcachier.tutorial;

  import java.lang.Iterable;

  public interface CachedTaskRepository {

    public Iterable<Task> findAllCached();

  }
  1. このインターフェースの実装を src/main/java/com/memcachier/tutorial/TaskRepositoryImpl.java​ に作成します。
  package com.memcachier.tutorial;

  import java.lang.Iterable;

  import org.springframework.beans.factory.annotation.Autowired;
  import com.google.code.ssm.api.ReadThroughAssignCache;

  public class TaskRepositoryImpl implements CachedTaskRepository {

    @Autowired
    TaskRepository taskRepository;

    @ReadThroughAssignCache(namespace="Taskrepo", assignedKey="all")
    public Iterable<Task> findAllCached() {
      return this.taskRepository.findAll();
    }
  }

実装のファイル名で従う必要がある命名規則は <REPOSITORY-NAME>Impl.java​ です。

TaskRepository​ の CRUD インターフェースの残り部分には、@Autowired​ 参照を追加するだけでアクセスできます。

ここで、@ReadThroughAssignCache​ アノテーションを介してキャッシングが発生します。すべての @ReadThrough*Cache​ アノテーションでは、次の処理を行います。

  • 値がキャッシュにあるかどうかチェックし、ある場合はその値を返します。
  • キャッシュにない場合は、関数を実行してその値を返し、その値をキャッシュにも保存します。

このアノテーションの Assign​ バージョンでは、アノテーションで宣言された割り当て済みのキーを使用します。これらのアノテーションについての詳細は、Simple Spring Memcached のドキュメント​を参照してください。

  1. 必ず、この実装を TaskRepository​ に統合してください。 これは単に、TaskRepository​ インターフェースにも CachedTaskRepository​ インターフェースを拡張させることによって行います。
  // ...
  public interface TaskRepository extends CrudRepository<Task, Long>, CachedTaskRepository {}

キャッシングアノテーションに関する注意事項: Spring ではキャッシングアノテーションの処理に プロキシを使用します。このため、コントローラーの内部にプライベートメソッドを作成して キャッシュアノテーションを追加しても、メソッドがキャッシュされることは期待できません。簡単に 言うと、キャッシュされるメソッドは、そのインターフェースを介してアクセスされるコンポーネントの 一部でなければなりません。詳細は、 StackOverflow のこのスレッド と、そこで言及されているリファレンスをご覧ください。

すべてのタスクをキャッシュするためのメソッドは用意できましたが、それらのメソッドを機能させるためには、src/main/java/com/memcachier/tutorial/Task.java​ で Task のデータ型のシリアル化を可能にする必要があります。

// ...
import java.io.Serializable;

public class Task implements Serializable {
  // ...
}

最後に、src/main/java/com/memcachier/tutorial/TaskController.java​ のコントローラーで、キャッシュされたタスクを取得できるようになりました。

// ...
public String showAllTasks(ModelMap model) {
  Iterable<Task> tasks = this.taskRepo.findAllCached();
  // ...
}
// ...

この新しい機能をデプロイしてテストしてみましょう。

$ git add .
$ git commit -m 'Add caching with MemCachier'
$ git push heroku master
$ heroku open

キャッシュ内で何が起きているかを見るために、MemCachier のダッシュボードを開きます。

$ heroku addons:open memcachier

タスクリストを最初に読み込むと、get miss と set コマンドが増加しているはずです。それ以降は、タスクリストを再読み込みするたびに get hit が増加するはずです (ダッシュボードの統計を更新してください)。

キャッシュは機能していますが、まだ大きな問題があります。新しいタスクを追加して結果を確認します。新しいタスクが現在のタスクリストに反映されていません。新しいタスクがデータベースに作成されましたが、アプリで表示されているのはキャッシュから取得した古いタスクリストです。

古いデータのクリア

データをキャッシュするだけでなく、古くなったデータを無効化することも重要です。この例では、新しいタスクが追加されるか既存のタスクが削除されるたびに、キャッシュされたタスクリストは古くなります。この 2 つの操作のどちらかが実行されるたびに、キャッシュを確実に無効化する必要があります。

キャッシュをクリアするラッパーを、TaskRepository​ の save メソッドと delete メソッドに追加することができます。 これは、次の 2 つの手順で行います。

  1. src/main/java/com/memcachier/tutorial/CachedTaskRepository.java​ で、CachedTaskRepository​ インターフェースにラッパーメソッドを宣言します。
  // ...
  public interface CachedTaskRepository {
    public Iterable<Task> findAllCached();
    public Task saveAndClearCache(Task t);
    public void deleteByIdAndClearCache(Long id);
  }
  1. src/main/java/com/memcachier/tutorial/TaskRepositoryImpl.java​ でラッパーメソッドを実装します。
  // ...
  import com.google.code.ssm.api.InvalidateAssignCache;

  public class TaskRepositoryImpl implements CachedTaskRepository {
    // ...

    @InvalidateAssignCache(namespace="Taskrepo", assignedKey="all")
    public Task saveAndClearCache(Task t){
      return this.taskRepository.save(t);
    }

    @InvalidateAssignCache(namespace="Taskrepo", assignedKey="all")
    public void deleteByIdAndClearCache(Long id){
      this.taskRepository.deleteById(id);
    }
  }

ここでは、古くなったデータが @InvalidateAssignCache​ アノテーションを介して無効化されます。 @ReadThroughAssignCache​ と同様に、これは、アノテーションで宣言された割り当て済みのキーに対して機能します。

タスクの追加または削除のリクエストが発生するたびに、コントローラーでこれらのラッパー関数を使用してキャッシュをクリアできるようになりました。そのためには、save​ と deleteById​ (src/main/java/com/memcachier/tutorial/TaskController.java​ 内) を saveAndClearCache​ と deleteByIdAndClearCache​ に置き換えます。次のようになります。

// ...
@RequestMapping(method = RequestMethod.POST)
public String newTask(ModelMap model,
                      @ModelAttribute("newTask") @Valid Task task,
                      BindingResult result) {
  if (!result.hasErrors()) {
    this.taskRepo.saveAndClearCache(task);
  }
  return showAllTasks(model);
}

@RequestMapping(method = RequestMethod.DELETE)
public String deleteTask(ModelMap model, @RequestParam("taskId") Long id) {
  this.taskRepo.deleteByIdAndClearCache(id);
  return showAllTasks(model);
}

修正されたタスクリストをデプロイします。

$ git commit -am 'Clear stale data from cache'
$ git push heroku master
$ heroku open

新しいタスクを追加すると、タスクリストのキャッシングの実装以降に追加したすべてのタスクがリストに表示されます。

参考情報と資料

  • MemCachier アドオンページ
  • MemCachier ドキュメント
  • Memcache の高度な使用法
  • Heroku Spring Boot ガイド
  • Simple Spring Memcached のドキュメント
  • Spring でのキャッシングに関するガイド
  • Spring でのキャッシングに関するドキュメント

関連カテゴリー

  • Spring Boot の使用

Information & Support

  • Getting Started
  • Documentation
  • Changelog
  • Compliance Center
  • Training & Education
  • Blog
  • Support Channels
  • Status

Language Reference

  • Node.js
  • Ruby
  • Java
  • PHP
  • Python
  • Go
  • Scala
  • Clojure
  • .NET

Other Resources

  • Careers
  • Elements
  • Products
  • Pricing
  • RSS
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku Blog
    • Heroku News Blog
    • Heroku Engineering Blog
  • Twitter
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku
    • Heroku Status
  • Github
  • LinkedIn
  • © 2025 Salesforce, Inc. All rights reserved. Various trademarks held by their respective owners. Salesforce Tower, 415 Mission Street, 3rd Floor, San Francisco, CA 94105, United States
  • heroku.com
  • Legal
  • Terms of Service
  • Privacy Information
  • Responsible Disclosure
  • Trust
  • Contact
  • Cookie Preferences
  • Your Privacy Choices