1回のトランザクションコミットエラー
3693 ワード
JPA監査機能を使用すると、プロジェクトのアンケート保存中に次のようなエラーが発生し、エラー情報からjpaトランザクションのコミット中にエラーが発生したことがわかります.
当時はアンケート保存中でした
自動的にuserを設定し、保存前に作成時間を設定し、保存後にtoken操作を設定します.userを設定した後にトランザクションをコミットした疑いがあり、token操作を設定してタイムズをコミットするのは間違っています.さらに,@CreatedBy注記と@PostPersist注記を併用できないという結論が得られた.
解決する
saveメソッドにトランザクション注釈を追加してみます.結局、報告を間違えた.
監査機能を有効にすると、データベースの操作時に常に現在のログインユーザーが取得されます.私たちの前の方法は、データベースからクエリーすることです.問題が見つかりました.残りは、この方法でデータベースを操作しないようにすることです.最も簡単な考え方は、フロントのようにキャッシュを設定することです.ユーザーがログインするときにuserを設定し、現在のログインユーザーを取得するときにデータベース操作を行わずにuserに直接戻ります.
カスタムAuthUserクラス
ログイン時にAuthUserクラス構築関数を実行し、user値を付与
現在のログインユーザーを取得するときにgetUser()メソッドを呼び出し、データベースの操作やトランザクションのコミットを回避します.
まとめ
バグを解決するには、エラーの流れを熟知し、どこが間違っているのかを知ってから、解決策を考えなければなりません.
2021-03-20 14:52:04.570 ERROR 21225 --- [io-8002-exec-10] c.y.q.e.GlobalExceptionHandler : : 127.0.0.1 http://localhost/admin/questionnaire Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction
当時はアンケート保存中でした
@CreatedBy
private User createUser;
/**
* .
*/
@PrePersist
public void initCreateTime() {
this.createTime = new Timestamp(System.currentTimeMillis());
}
/**
* token.
*/
@PostPersist
public void initToken() {
...
}
自動的にuserを設定し、保存前に作成時間を設定し、保存後にtoken操作を設定します.userを設定した後にトランザクションをコミットした疑いがあり、token操作を設定してタイムズをコミットするのは間違っています.さらに,@CreatedBy注記と@PostPersist注記を併用できないという結論が得られた.
解決する
saveメソッドにトランザクション注釈を追加してみます.結局、報告を間違えた.
@PrePersist
@PostPersist
注記を必要とするメソッドをエンティティリスナーに移動しようとしたが、結果はエラーであった.設定tokenメソッドをmレイヤに配置し、リスナーがmレイヤを呼び出してtokenメソッドを設定すると、リスナーはmレイヤに注入できません.切断面はtoken設定を完了し、試行しませんでした.m層save法について集積テストを行い,他の影響を排除し,正しく実行できることを発見し,@CreatedBy注釈と@PostPersist注釈の衝突問題を排除し,問題は別の場所にある.ログレベルをdebugに変更し、エラーの原因を確認します.スタック情報によると、データベースを操作してトランザクションをコミットした結果、現在のログインユーザを取得した後、@CreateBy注釈が再びデータを更新するときにトランザクションが使用できないように、アンケートを保存する過程で現在のログインユーザを取得する方法が実行されていることが分かった./**
* .
*/
private class SpringSecurityAuditorAware implements AuditorAware {
@Autowired
private UserService userService;
@Override
public Optional getCurrentAuditor() {
User user = this.userService.getCurrentLoginUser();
if (user == null) {
throw new RuntimeException(" ");
}
return Optional.of(user);
}
}
監査機能を有効にすると、データベースの操作時に常に現在のログインユーザーが取得されます.私たちの前の方法は、データベースからクエリーすることです.問題が見つかりました.残りは、この方法でデータベースを操作しないようにすることです.最も簡単な考え方は、フロントのようにキャッシュを設定することです.ユーザーがログインするときにuserを設定し、現在のログインユーザーを取得するときにデータベース操作を行わずにuserに直接戻ります.
/**
* , , @CreateBy.
*/
public static class AuthUser extends org.springframework.security.core.userdetails.User {
private User user;
public AuthUser(User user, Collection extends GrantedAuthority> authorities) {
super(user.getUsername(), user.getPassword(), authorities);
this.user = user;
}
public AuthUser(User user,
boolean enabled,
boolean accountNonExpired,
boolean credentialsNonExpired,
boolean accountNonLocked,
Collection extends GrantedAuthority> authorities) {
super(user.getUsername(),
user.getPassword(),
enabled,
accountNonExpired,
credentialsNonExpired,
accountNonLocked,
authorities);
this.user = user;
}
public User getUser() {
return user;
}
protected void setUser(User user) {
this.user = user;
}
}
カスタムAuthUserクラス
logger.debug(" ");
return new AuthUser(
user,
true,
true,
true,
user.isNonLocked(),
authorities);
ログイン時にAuthUserクラス構築関数を実行し、user値を付与
UserServiceAuth.AuthUser authUser =
(UserServiceAuth.AuthUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
user = authUser.getUser();
現在のログインユーザーを取得するときにgetUser()メソッドを呼び出し、データベースの操作やトランザクションのコミットを回避します.
まとめ
バグを解決するには、エラーの流れを熟知し、どこが間違っているのかを知ってから、解決策を考えなければなりません.