LoginSignup
0
0

More than 1 year has passed since last update.

アノテーションベースの MyBatis で one-to-one / one-to-many のテーブルを1クエリでとってくる方法

Last updated at Posted at 2022-07-07

積年の疑問が晴れた。が、だいぶゴツい。

サマリ

  • one-to-many のときは、@One アノテーションに columnPrefix / resultMap を使う
  • many-to-many のときは、@Many アノテーションでおなじようにすればできるはず(未検証)

背景

過去、アノテーションベースでは N+1 問題が回避不可だった

しかし、@Oneや@Manyでは上記と同じことを実現できず、必ず他の select を実行するしかありません。
select を利用する方法は N+1 問題が起きてしまうのが嫌で、個人的にはあまり使っていなかったので、ここはちょっとデメリットかなと思いました。

mybatis-3.5.5 で解消した模様

mybatis-3.5.5 で @One @Many に columnPrefix を指定できるようになった。
これにより、N + 1 問題を発生させずに、1クエリで one-to-one / one-to-many テーブルをとってこれるようになった。

コード例

こんな感じのテーブルのとき

CREATE TABLE IF NOT EXISTS users (
  id UUID PRIMARY KEY,
  username text NOT NULL UNIQUE,
);

CREATE TABLE IF NOT EXISTS articles (
  id UUID PRIMARY KEY,
  user_id UUID NOT NULL references users(id), -- one-to-one relationship
  body text NOT NULL,
);

こうする

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.One;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface ArticleRepository {

    @Select("""
            SELECT
                a.id
              , a.user_id
              , a.body
              , u.id as user_id
              , u.username as user_username
            FROM articles a
            JOIN users u on a.user_id = u.id
            """)
    @Results(value = {
            @Result(id = true, column = "id", property = "id"),
            @Result(column = "body", property = "body"),
            @Result(property = "user", one = @One(resultMap = "userResultMap", columnPrefix = "user_"))
    })
    List<ArticleRecord> select();

    @Select("SELECT '1'") // このクエリは実行されない。@ResultMap を定義するためのダミークエリ
    @Results(id = "userResultMap", value = {
            @Result(id = true, column = "id", property = "id"),
            @Result(column = "username", property = "username"),
    })
    UserRecord __userResultMap();
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0