🐾

Mybatisの2ndレベルキャッシュとキャッシュなしの速度比較

2025/01/27に公開

概要

Mybatisの2ndレベルキャッシュが使用される場合と使用されない場合の速度比較を行います。クエリを実行するステートメントを10万回呼び出して速度比較を行った結果、以下のような結果が得られました。

2ndレベルキャッシュ 実行時間
あり 0.946459000
なし 33.330857000

確認環境

  • Java 21
  • Spring Boot 3.4.1
  • MyBatis Spring Boot Starter 3.0.4
  • PostgreSQL 16.4

確認方法

2ndレベルキャッシュを使用する場合、キャッシュを使用しない場合のそれぞれを計測し、キャッシュ使用時と未使用時の速度差を求めます。

依存関係

build.gradle.kts
dependencies {
    implementation("org.springframework.boot:spring-boot-starter:3.4.1")
    implementation("org.springframework.boot:spring-boot-starter-jdbc:3.4.1")
    implementation("org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.4")
    implementation("org.postgresql:postgresql:42.7.4")
}

データベース

テーブル定義

テーブル
                     Table "public.example"
 Column |         Type          | Collation | Nullable | Default 
--------+-----------------------+-----------+----------+---------
 id     | character varying(4)  |           | not null | 
 memo   | character varying(50) |           |          | 

データ

データ
Table "public.example"
  id  |   memo   
------+----------
 0001 | example1
 0002 | example2

2ndレベルキャッシュの速度確認プログラム

構成
com.example
  +- ExampleApplication.java
  +- ExampleApplicationRunner.java
  +- ExampleRepository.java
  +- ExampleMapper.java
  +- ExampleMapper.xml

ExampleApplication はアプリケーションのエントリポイントです。

ExampleApplication.java
package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

ExampleApplicationRunnerApplicationRunner を実装します。このクラスがアプリケーション起動時に呼び出されます。

ExampleApplicationRunner.java
package com.example;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.time.LocalDateTime;

@Component
public class ExampleApplicationRunner implements ApplicationRunner {
    private final Logger log = LoggerFactory.getLogger(ExampleApplicationRunner.class);

    private ExampleRepository exampleRepository;

    public ExampleApplicationRunner(ExampleRepository exampleRepository) {
        this.exampleRepository = exampleRepository;
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("一度実行してキャッシュする");
        exampleRepository.get();

        log.info("計測する");
        LocalDateTime start = LocalDateTime.now();
        exampleRepository.get2();
        LocalDateTime end = LocalDateTime.now();
        Duration duration = Duration.between(start, end);
        log.info("*** {}.{} ***", duration.getSeconds(), duration.getNano());
    }
}

ExampleRepository はデータソースへアクセスするためのクラスです。

ExampleRepository.java
package com.example;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@Repository
public class ExampleRepository {
    private final Logger log = LoggerFactory.getLogger(ExampleRepository.class);

    private ExampleMapper exampleMapper;

    public ExampleRepository(ExampleMapper exampleMapper) {
        this.exampleMapper = exampleMapper;
    }

    @Transactional
    public void get() {
        exampleMapper.get("0001");
    }

    @Transactional
    public void get2() {
        for (int i = 0; i < 100000; i++) {
            exampleMapper.get("0001");
        }
    }
}

ExampleMapper ではデータベース操作に対応するメソッドを宣言します。

ExampleMapper.java
package com.example;

import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

@Mapper
public interface ExampleMapper {
    List<Map<String, Object>> get(@Param("id") String id);
}

ExampleMapper.xml にクエリを記述します。

ExampleMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="com.example.ExampleMapper">
    <cache/>
    <select id="get" resultType="hashmap">
        select * from example where id = #{id};
    </select>
</mapper>

2ndレベルキャッシュとキャッシュなしの速度確認結果

まずは2ndレベルキャッシュ使用時の速度を確認します。

結果
com.example.ExampleApplicationRunner     : *** 0.946459000 ***

次に、ExampleMapper.xml から <cache/> を削除してキャッシュなしの速度を確認します。

結果
com.example.ExampleApplicationRunner     : *** 33.330857000 ***

Discussion