作記録

記憶代わり

Spring Frameworkの@Transactionalについて

結論

Spring Frameworkでよく見受けられる下記のような設計をするのであれば@Transactionalは、application層ではなくinfrastructure層で使うべきだと思う。

presentation層(@Controller)
application層(@Service)
infrastructure層(@Repository) 

説明

org.springframework.transaction.annotation.Transactional アノテーションをapplication層などのServiceクラスで利用しているケースに遭遇する。

Springの@Transactionalについてのガイド を見ると下記の記述がある。

このガイドでは、データベース操作を非侵入型トランザクションでラップするプロセスについて説明します。

上記の通り@Transactionalはデータベース操作の関心事なので、application層のServiceクラスではなく、infrastructure層のDB操作を行っている層で書くのが適切だと思う。

ガイドのコード例について

上記の Springの@Transactionalについてのガイド を見ると下記のようなコードがある。

package com.example.managingtransactions;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
public class BookingService {

  private final static Logger logger = LoggerFactory.getLogger(BookingService.class);

  private final JdbcTemplate jdbcTemplate;

  public BookingService(JdbcTemplate jdbcTemplate) {
    this.jdbcTemplate = jdbcTemplate;
  }

  @Transactional
  public void book(String... persons) {
    for (String person : persons) {
      logger.info("Booking " + person + " in a seat...");
      jdbcTemplate.update("insert into BOOKINGS(FIRST_NAME) values (?)", person);
    }
  }

  public List<String> findAllBookings() {
    return jdbcTemplate.query("select FIRST_NAME from BOOKINGS",
        (rs, rowNum) -> rs.getString("FIRST_NAME"));
  }

}

名称を見るとServiceクラスだが、実際の処理内容を見るとやはりDB操作をしている。

よって、やはりinfrastructure層のDB操作をしているメソッドなどに@Transactionalをつけるべきだと思う。