在应用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

过后在保留问卷过程中存在

@CreatedByprivate User createUser;/** * 在保留之前设置发明工夫.  */ @PrePersistpublic void initCreateTime() {  this.createTime = new Timestamp(System.currentTimeMillis());}/** * 在保留之后设置token.  */ @PostPersistpublic 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<User> {  @Autowired private UserService userService; @Override public Optional<User> 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()办法,从而防止操作数据库,对事务进行提交。

总结

解决bug应该相熟出错的流程,晓得到底哪里错了,而后再想解决方案。