Spring Bootエラー「No EntityManager with ~」

DBと連携したSpring Bootアプリの実行時に「TransactionRequiredException: No EntityManager with ~」というエラー(例外)が出たので、この解決方法について説明しています。

※ 本ページはプロモーションが含まれています。

目的と動作環境

最終更新日:2023/2/19

Spring Bootのウェブアプリを開発していて、ウェブアプリ実行時に下記の「TransactionRequiredException: No EntityManager with〜」エラー(というか例外)が発生したので、この例外を解決するためにやった事などを書いています。

2023-02-17 00:22:15.098 ERROR 13332 --- [nio-8080-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: No EntityManager with actual transaction available for current thread - cannot reliably process 'remove' call; nested exception is javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'remove' call] with root cause

javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'remove' call
	
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:295) ~[spring-orm-5.3.25.jar:5.3.25]
〜

◾️動作環境とバージョン情報です
Spring Bootバージョン:2.7.8
Java:11
MySQL:MySQL Community Edition 8.0.31
開発環境:Eclipse(Pleiades All in One、4.16(2020-06)、Java Full Edition版)
OS:macOS Big Sur(バージョン11.7.3)

問題のエラーについての詳細

上記エラーが発生した時の詳細についてもう少し書いておきます。

DB(MySQL)と連携したSpring Bootアプリで、RegisteredUserテーブルのインタフェース(Spring Data JPAのCrudRepositoryを継承)があり、RegisteredUserテーブルのusernameカラムを条件にレコードを削除するメソッドを用意しておきました。

//RegisteredUserのリポジトリインタフェース
public interface RegisteredUserRepository extends CrudRepository<RegisteredUser, Integer> {
	//RegisteredUserテーブルのusernameカラムを条件にレコードを削除する
	void deleteByUsername(String username);
}
そしてこのリポジトリをサービスクラスから呼び出すようにします(もちろんコントローラクラスから呼び出してもOK)。
@Service
public class RegisteredUserService {
	@Autowired
	RegisteredUserRepository registeredUserRepository;

	public void deleteByUsername(String username) {
		registeredUserRepository.deleteByUsername(username);
	}
}

これで、Spring Bootアプリ実行中にサービスクラスの「registeredUserRepository.deleteByUsername(username);」の部分が実行されるタイミングで冒頭のエラーが出るようになりました。

Eclipseのコンソールにはdelete SQLのログは出力されてなかったので、delete SQL自体が実行された形跡は無しでした。

ちなみにSpring Boot(Spring Data JPA)でHibernateのSQLログを出力したい場合、application.propertiesファイルにspring.jpa.show-sqlを指定すればできます。

spring.jpa.show-sql=true

エラーの解決方法。@Transactionalアノテーション

それでは問題のエラーの解決方法についてです。

サービスクラスのdeleteByUsernameメソッドに@Transactionalアノテーションを付けたら、ちゃんとdelete SQLが実行されるようになりました。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
〜

@Service
public class RegisteredUserService {
	@Autowired
	RegisteredUserRepository registeredUserRepository;

	@Transactional
	public void deleteByUsername(String username) {
		registeredUserRepository.deleteByUsername(username);
	}
}
(*ちなみに@Transactionalは"javax.transaction.Transactional"を使っても動作した。)

再度問題のエラーログをしっかり確認してみたらTransactionRequiredException例外とあるので、どうやらリポジトリで実行するSQLによってはちゃんと@Transactionalを付けてトランザクションにする必要があるみたいですね。

もう1つの問題。Eclipseでデバッグ起動をするとJavaブレークポイントのアラートが頻出

これでSpring Bootアプリは問題なく動作するようになったのですが、Eclipseで@Transactionalを付けたメソッド内にデバッグのブレークポイントを付けてデバッグ起動したら、「Javaブレークポイント。行番号が見つからないため、〜。欠落した行番号情報」というアラートウインドウが頻繁に出るようになりました(自分の環境だけかも)。
Eclipseでアラート。Javaブレークポイント。行番号が見つからないため〜

ちょっと意味の分からないアラートですが、Ecllipseの設定でこのアラートを出ないようにする事はできます。
Eclipseの設定ウインドウを開いてサイドメニューからJava->デバッグを選択して、「行番号属性が見つからないためにブレークポイントをインストールできない時に警告」というチェックボックスを外せばこの警告は出なくなります。

あと、@Transactionalを付けたメソッド内にデバッグのブレークポイントさえ付けなければアラートは全く出ないのでそこまで気にする必要はないかなと思います。

ですので反対に言えば、もしもEclipseでウェブアプリをデバッグ起動してJavaブレークポイントのアラートウインドウが出るようになった場合、アラートウインドウのメッセージに書いてあるメソッド内にデバッグのブレークポイントを付けている可能性があるのでそれを取るか、Eclipseの設定(Java->デバッグ)でこのアラートウインドウが出ないようにすれば解決できます。