JPA deleteのトラブルシューティングとトランザクション.


プロジェクトの進行中にJPAコードを作成中に予期せぬエラーが発生しました.
前提条件:Spring Data JPAのRepositoryは、命名規則に従ってクエリーを自動的に生成します.
(参考資料:Spring Data JPA命名規則。)
ユーザと課題の情報を用いて,マルチ対マルチマッピングの関係からEntityを削除しようとした.
ex)deleteByUserAndChallenge->userとchallengeのエンティティ情報を受信することによってクエリーを作成します.
この過程で、私たちは間違いに遭遇しました.私たちがいろいろな方法で知った概念をまとめたいと思います.
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;
次のエラーが発生し、removeを呼び出すことができません.
問題分析.
まず、現在のドメインは次のとおりです.
public class UserChallenge {

	@Id
	@GeneratedValue
	private Long id;

	@ManyToOne
	@JoinColumn(name = "USER_ID")
	private User user;

	@ManyToOne
	@JoinColumn(name = "CHALLENGE_ID")
	private Challenge challenge;
}
ユーザーと質問をマップするには、次のように、新しいドメインで関係をManyToOneにマップしました.
saveは正常ですが、findByUserAndChallengeは上記のエラーを投げ出すので、PKをインポートした部分でエラーになる可能性があるので、Domainのプライマリ・キーを変更して実行しました.
プロセスID->(ユーザPK、質問PK)を使用してデフォルトキーを変更します.
@IdClass(UserChallengePK.class)
public class UserChallenge {

	@Id
	@ManyToOne
	@JoinColumn(name = "ID")
	private User user;

	@Id
	@ManyToOne
	@JoinColumn(name = "CHALLENGE_ID")
	private Challenge challenge;
}
ドメインのプライマリ・キーを次のように変更します.
public class UserChallengePK implements Serializable {
	private Integer user;
	private Long challenge;
}
public interface UserChallengeRepository extends JpaRepository<UserChallenge, UserChallengePK> {
	UserChallenge save(UserChallenge userChallenge);
	void deleteByUserAndChallenge(User user, Challenge challenge);
}
プライマリ・キーに関する情報を入力して実行しましたが、結果は同じです.
deleteBy~の操作では,誤った仮定はPKではなく値によって消去される.
プロセスdeleteBy~をブラウズする動作.
後述するユーザ、質問中のパラメータが無効であるかどうか、deleteByIdおよびdeleteBy~の動作を検索する方法を決定します.
まず、JPA RepositoryのdeleteとdeleteByIdコードを参照してください.


deleteの場合、entitymanagerのremove関数を使用して、永続性コンテキストがクリアされているかどうかを確認できます.
deleteByIdはfindByIdを使用して永続性コンテキストをインポートし、deleteの呼び出しを確認できます.
また、JPAの方法でクエリーを生成するプロセスは、次のとおりです.
Stackoverflowでは良い説明がありました.( リンク )
Proxyアレイを使用し、メソッドインタフェースの機能を使用してPartTreeに従ってメソッドを作成します.すなわち,queryの作成方式はfindBy~とdeleteBy~と変わらないので,一つの方法を試みた.
  • FindByUserAndChallenge検索Entity.
  • delete Entity持続性を削除します.
  • プログラム作成後の結果を確認しました:
    コースfindById、delete、deleteByIdの違いを検索します.
  • FindByUserAndChallenge->Delete(T Entity):操作O
  • ByUserAndChallengeの削除:操作X
  • ここで、エラーメッセージを再度確認し、delete内部ライブラリを確認したところ、漏れが見つかりました.
    "No EntityManager with actual transaction available for current thread"
    後でthreadに関連するエラーを確認しdeleteの関数を確認しました.
    @Transactional音声認識.
    デフォルトでは、JPAはトランザクションを提供するので、2つ以上のDBでなければトランザクションを適用する必要はないというエラーが発生します.
  • ドメイン変更
  • @Transactional
    public void leaveChallenge(Long id, User user){
    	Challenge findChallenge = isExistChallenge(id);
    
    	userChallengeRepository.deleteByUserAndChallenge(user, findChallenge);
    }
    トランザクションを上記のサービスの関数に適用すると、エラーが解決されます.
    トラブルシューティングと考察
    データベースにアクセスすると、読み込みはトランザクションにあまり影響しませんが、deleteやinsertのように直接データベースを変更する動作がロックされているか、コミットに基づいてロールバックされているか、トランザクションに敏感であることを再確認できます.
    +追加する内容や不足点があれば、メッセージを残してください!:)