@Transactionalとは?
Springではクラスやメソッド、及びインタフェースに付ける@Transactionalというアノテーションを提供している。
@Transactionalを付けたら、*宣言的トランザクションの管理対象になりトランザクションの属性が付与される。
*宣言的トランザクション:AOPを利用し、コードの外部からトランザクションの機能を付与し属性を指定できるようにすること。⇔明示的トランザクション
使用例
サービスレイヤー
@Transactionalはどこでも使えるが、一般的にビジネスロジックに該当するサービスレイヤーのメソッドに書くのが良い。なぜなら、DBから取得したデータを取り扱うところがサービスレイヤーだからだ。
@Transactional(readOnly = true) //★1
@Service
public class WordsService {
private final WordsRepository wordsRepository;
public List<WordHomeResponseDto> getAllWords() {
List<Words> result = wordsRepository.findByDeleteFlg(GlobalVariable.FALSE);
List<WordHomeResponseDto> words = result.stream().map(WordHomeResponseDto::new).collect(Collectors.toList());
return words;
}
@Transactional //★2
public void edit(WordEditRequestDto requestDto) {
Words word = wordsRepository.findByWordId(requestDto.getWordId()).orElseThrow(() -> new IllegalArgumentException("該当することばがありません。"));
word.update(requestDto.getWordName(), requestDto.getWordPronunciation(), requestDto.getWordMeaning(), requestDto.getWordExample());
}
}
★1:クラスレベルに@Transactionalアノテーションを付けるとその下のメソッドにも全て適用される。つまりgetAllWords()
にも@Transactionalが付与されている状態。
★2:★1のように、クラスレベルには全てのメソッドに適応される読み取り専用(readOnly = true)@Transactionalを宣言し、insert, update, delete
をする場合は別途@Transactionalをメソッドに付与するのが良い。微妙な性能の改善ができるようだ。
テストコード
@Transactional //★
@DataJpaTest
public class WordsRepositoryTest {
@Autowired
private WordsRepository wordsRepository;
@Test
public void updateWord() {
//given
String wordName = "test-word-update";
String wordPronunciation = "test-pronunciation-update";
String wordMeaning = "test-meaning-update";
String wordExample = "did you update your test code?";
List<Words> originalWordList = wordsRepository.findAll();
Words word = originalWordList.get(0);
//when
word.update(wordName, wordPronunciation, wordMeaning, wordExample);
List<Words> editedWordList = wordsRepository.findAll();
word = editedWordList.get(0);
//then
assertEquals(word.getWordName(), wordName);
assertEquals(word.getWordPronunciation(), wordPronunciation);
assertEquals(word.getWordMeaning(), wordMeaning);
assertEquals(word.getWordExample(), wordExample);
}
}
@Transactionalをテストに付けたら、テストコードで行ったDBに対する作業(例えば登録・更新・削除)をテスト完了後ロールバックしてくれる。但し、auto_increment
やsequence
で増加したid
はトランザクションの管理対象ではないので、ロールバックされない。