ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
| この記事の要点 |
|
エラー内容
Spring Data JPA のリポジトリで @Query + UPDATE/DELETE を実行すると以下が発生:
Caused by: java.lang.RuntimeException: Executing an update/delete query;
nested exception is javax.persistence.TransactionRequiredException:
Executing an update/delete query
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(...)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(...)
at ...
原因
JPA の仕様では UPDATE / DELETE / INSERT クエリは必ずトランザクション内で実行する必要があります。SELECT は不要ですが、データ変更系には明示的なトランザクション境界が要求されます。
Spring Data JPA はデフォルトでリポジトリメソッドに read-only トランザクションを開きますが、@Modifying 付きの更新クエリには別途指定が必要です。
発生する典型コード
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// ❌ NG: @Modifying と @Transactional がない
@Query("UPDATE User u SET u.lastLoginAt = :now WHERE u.id = :id")
void updateLastLogin(@Param("id") Long id, @Param("now") LocalDateTime now);
}
@Service
public class LoginService {
@Autowired
private UserRepository userRepository;
public void onLogin(Long userId) {
// ↓ ここで TransactionRequiredException
userRepository.updateLastLogin(userId, LocalDateTime.now());
}
}
対処1: リポジトリで @Modifying + @Transactional
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
@Modifying // ★ UPDATE/DELETE クエリには必須
@Transactional // ★ 更新トランザクションを開く
@Query("UPDATE User u SET u.lastLoginAt = :now WHERE u.id = :id")
void updateLastLogin(@Param("id") Long id, @Param("now") LocalDateTime now);
}
@Modifying はこのクエリが SELECT ではないことを Spring に伝えます。これが無いと「結果セットが返ってこない」エラーになります。
@Transactional はメソッド呼び出し時にトランザクションを開始します。
対処2: Service 層に @Transactional(推奨)
リポジトリではなく、Service 層でトランザクション境界を引く方が設計上きれい。複数の更新を 1 トランザクションでまとめられます:
@Service
public class LoginService {
@Autowired
private UserRepository userRepository;
@Autowired
private LoginLogRepository loginLogRepository;
@Transactional // ★ Service のメソッド単位でトランザクション
public void onLogin(Long userId) {
userRepository.updateLastLogin(userId, LocalDateTime.now());
loginLogRepository.save(new LoginLog(userId, LocalDateTime.now()));
// 両方コミット or 両方ロールバック
}
}
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
@Modifying // ★ これは依然として必要
@Query("UPDATE User u SET u.lastLoginAt = :now WHERE u.id = :id")
void updateLastLogin(@Param("id") Long id, @Param("now") LocalDateTime now);
}
@Modifying のオプション
| オプション | 動作 | 用途 |
|---|---|---|
| flushAutomatically = true | クエリ実行前に永続化コンテキストを flush | 同じトランザクション内で entity 変更と直接 UPDATE 両方使う場合 |
| clearAutomatically = true | クエリ実行後に永続化コンテキストをクリア | UPDATE 後にエンティティをロードし直したい場合 |
@Modifying(flushAutomatically = true, clearAutomatically = true)
@Transactional
@Query("UPDATE User u SET u.status = :status WHERE u.id = :id")
int updateStatus(@Param("id") Long id, @Param("status") String status);
戻り値の意味
@Modifying 付きメソッドは戻り値で更新行数を取得できます:
@Modifying
@Transactional
@Query("UPDATE User u SET u.deleted = true WHERE u.expiredAt < :now")
int softDeleteExpired(@Param("now") LocalDateTime now);
// 呼び出し
int count = userRepository.softDeleteExpired(LocalDateTime.now());
log.info("論理削除した行数: {}", count);
JpaRepository.save() は何故問題ないか
save() や delete() など Spring Data JPA の標準メソッドは内部で自動的にトランザクションを開く設計です。手動の @Query UPDATE/DELETE だけが明示的な指定を必要とします。
| メソッド | トランザクション | @Modifying |
|---|---|---|
save() / saveAll() | 自動 | 不要 |
delete() / deleteAll() | 自動 | 不要 |
@Query SELECT ... | 不要(read-only) | 不要 |
@Query UPDATE/DELETE ... | ★ 必要 | ★ 必要 |
@Query INSERT ... (ネイティブ) | ★ 必要 | ★ 必要 |
@Transactional の付け場所のベストプラクティス
- Service クラスのメソッドに付けるのが基本(トランザクション境界 = ビジネスロジック単位)
- リポジトリの個別メソッドに付けるのは「単独で UPDATE するメソッド」だけ
- クラスレベル
@Transactionalでクラス全メソッドを対象にできる - readOnly = true を SELECT 系メソッドに付けるとパフォーマンス向上
- 例外時のロールバック: デフォルトは
RuntimeExceptionのみ。checked例外でロールバックさせるにはrollbackFor = Exception.class
関連エラー
- "Not supported for DML operations" — JPQL でなくネイティブクエリで UPDATE/DELETE する場合 →
@Query(value = "...", nativeQuery = true) - "No EntityManager with actual transaction available" — Service 層に
@Transactional付け忘れの典型 - "Cannot acquire transaction" — DataSource 設定ミス / 接続プール枯渇
- "Could not commit JPA transaction" — コミット時の制約違反 / 楽観ロック失敗など
ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
子ページ
子ページはありません
同階層のページ
- java.lang.IllegalStateException: CGLIB is required to process @Configuration classes
- Error creating bean with name 'org.springframework.aop.config.internalAutoProxyCreator': Instantiation of bean failed; nested exception is java.lang.NoClassDefFoundError: Could not initialize class org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
- No mapping found for HTTP request with URI ... in DispatcherServlet with name ...
- An internal error occurred during: "Building UI model". com/google/common/base/Function
- No identifier specified for entity : ...
- org.hibernate.hql.internal.ast.QuerySyntaxException: table_name is not mapped
- No compiler is provided in this environment
- java.sql.SQLException: The server time zone value ' ... ' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone
- Caused by: java.lang.RuntimeException: Executing an update/delete query
- Not supported for DML operations
- Field ... required a bean of type ... that could not be found.
- Annotation-specified bean name 'xxxController' for bean class [com.xxx.controller.xxxController] conflicts with existing, non-compatible bean definition of same name and class [com.xxx.xxxController]
- Whitelabel Error Page This application has no explicit mapping for /error, so you are seeing this as a fallback.
- Exception in thread "main" java.lang.UnsupportedClassVersionError
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 Spring Frameworkのアノテーション一覧
- 7 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- PHPでのファイルアップロード方法|multipart/form-dataと$_FILES 2026-08-07 17:15:57
- PHP $_SERVERとは|DOCUMENT_ROOT・PHP_SELFなど主な要素 2026-08-07 17:15:57
- Scratchのアカウントの作り方|メールアドレスとユーザー名の登録手順 2026-08-07 17:15:57
- djangoにおけるMVCアプリケーション実装例 2026-08-07 17:15:57
- Bluetoothとは|仕組み・BLEとClassicの違い・用途 2026-08-07 17:15:57
- Spring Bootのテスト入門|@SpringBootTestとJUnitでの単体・結合テスト 2026-08-07 17:15:57
- Java とは?言語仕様・JVM・主要フレームワーク一覧 2026-08-07 17:15:56
- インストール方法(Windows版) 2026-08-07 17:15:56
- APIキー取得方法 2026-08-07 17:15:56
- 【PHPフレームワーク】Laravelの使い方 2026-08-07 17:15:56
- Scratch 作品の公開方法 2026-08-07 17:15:56
- Google OAuth 2.0 認証の実装方法 2026-08-07 17:15:56
- データベースとは?RDB / NoSQL / SQL の基礎 2026-08-07 17:15:56
- インストール(eclipseプラグイン) 2026-08-07 17:15:56
- Spring Frameworkの使い方 2026-08-07 17:15:56
コメントを削除してもよろしいでしょうか?