1回のトランザクションコミットエラー


JPA監査機能を使用すると、プロジェクトのアンケート保存中に次のようなエラーが発生し、エラー情報からjpaトランザクションのコミット中にエラーが発生したことがわかります.
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に変更し、エラーの原因を確認します.一次事务提交错误_第1张图片スタック情報によると、データベースを操作してトランザクションをコミットした結果、現在のログインユーザを取得した後、@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()メソッドを呼び出し、データベースの操作やトランザクションのコミットを回避します.
まとめ
バグを解決するには、エラーの流れを熟知し、どこが間違っているのかを知ってから、解決策を考えなければなりません.