0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

springのTransactionalでロールバックされないお話

Last updated at Posted at 2024-06-10

springの @Transactional を使用するとメソッドの外に例外が伝播した際にロールバックしてくれます。
ただし(デフォルトでは)プロキシ経由の外部メソッド呼び出しのみが対象になるということで、所謂 @Autowired したインスタンスから呼び出すメソッドに @Transactional を付与する必要があります。
そこで以下のようなコードを組んだのですが、これは期待した通りの動きにはなりませんでした。

間違っている例
@Service
class ServiceA {
  @Transactional
  public void updateEntities(List<EntityA> entities) {
    // 全ての要素に対して UPDATE を実行して欲しい
    // エラーが起きても後続は処理を続ける
    for (Entity entity : entities) {
      try {
        update(entity)
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }

  @Transactional
  private void update(EntityA entity) {
    int cnt = dao.updateRecord(entity);
    if (cnt != 1) {
      // 更新件数が 1 で無ければ例外を投げてロールバックしたい
      throw new RuntimeException();
    }
  }
}

別のクラスから updateEntities() を呼び出し「全要素に対して処理を行いつつ、1 要素に対して更新件数が 1 で無ければその要素はロールバックしたい」という処理です。
これのテストを記述して試してみたところ、update() が例外を投げてもコミットされており、ロールバックされていませんでした。

主に間違っている点としては 2 つ

1. 内部呼び出しを行なっている

冒頭にもさらっと記載した通り、@Transactional に働いてもらうにはデフォルトでは別のクラスから呼ばれている必要があります。
今回 update() は同一クラスの updateEntities() から呼び出されてしまっています。

2. 可視性が private になっている

可視性は public である必要があるそうです(6.0 以降は protected または package private も可能とのこと)。

別クラスに切り出して対処

要素のカタマリを操作するクラスと単一の要素を操作するクラスに分けてしまおうという発想です。
クラスを分けてしまえば外部呼び出しの形になるので期待通りの動作となります。
また、ドキュメントを読んだだけで試していませんが mode を aspectj に変更し、設定を修正すれば自己呼び出しも対応可能なようです。

class ServiceA {
  public void updateEntities(List<EntityA> entities) {
    for (Entity entity : entities) {
      try {
        serviceB.update(entity)
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
}

class ServiceB {
  @Transactional
  private void update(EntityA entity) {
    int cnt = dao.updateRecord(entity);
    if (cnt != 1) {
      throw new RuntimeException();
    }
  }
}

教訓:ドキュメントを読む

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?