Spring Boot应用JPA审计配置后未生效问题求助
问题描述
已为Spring Boot应用配置JPA审计,但执行更新操作后数据库未生成审计记录,Hibernate的update语句也未包含审计字段。相关配置代码如下:
主类代码
@SpringBootApplication @EnableScheduling @ConfigurationPropertiesScan @EnableJpaAuditing(auditorAwareRef = "auditorAwareImpl") public class PlanetsApplication { public static void main(String[] args) { SpringApplication.run(PlanetsApplication.class, args); } }
Auditor实现类
@Component("auditorAwareImpl") public class AuditorAwareImpl implements AuditorAware<String> { @NotNull @Override public Optional<String> getCurrentAuditor() { return Optional.of("system"); } }
审计基类
@Getter @Setter @EntityListeners(AuditingEntityListener.class) @MappedSuperclass public class BaseEntity { @CreatedDate @Column(updatable = false) protected LocalDateTime createdAt; @CreatedBy @Column(updatable = false) private String createdBy; @LastModifiedDate @Column(updatable = false) protected LocalDateTime updatedAt; @LastModifiedBy @Column(updatable = false) protected String updatedBy; }
实体类
@Entity @Table(name = "t_spotify_playlist", uniqueConstraints = @UniqueConstraint(columnNames = {"playlistId", "sun", "moon"})) @Getter @Setter @AllArgsConstructor @NoArgsConstructor @Builder public class SpotifyPlayList extends BaseEntity implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String playlistId; @Column(length = 50) private String sun; @Column(length = 50) private String moon; // Many-to-Many relationship with SpotifyTrack @ManyToMany(fetch = FetchType.EAGER) @JoinTable( name = "t_playlist_track", // Join table name joinColumns = @JoinColumn(name = "playlist_id"), // Foreign key for SpotifyPlayListDesc inverseJoinColumns = @JoinColumn(name = "track_id") // Foreign key for SpotifyTrack ) private Set<SpotifyTrack> tracks; // Tracks associated with the playlist }
更新操作代码
SpotifyPlayList spotifyPlayList2 = spotifyPlayListService.findAll().stream().findAny().get(); spotifyPlayList2.setSun(spotifyPlayList2.getSun().toUpperCase()); spotifyPlayListService.save(spotifyPlayList2); log.info("saved {} ", spotifyPlayList2);
执行后数据库无审计记录,Hibernate生成的SQL如下:
Hibernate: update t_spotify_playlist set moon=?, playlist_id=?, sun=? where id=?
尝试移除BaseEntity部分字段的updatable=false属性,问题依旧。
解决方案
1. 修正更新类审计字段的updatable配置
@LastModifiedDate和@LastModifiedBy是用来记录更新操作的字段,不能设置updatable=false——该属性会让Hibernate判定这些字段不可更新,直接在update语句中忽略它们。修改BaseEntity:
@Getter @Setter @EntityListeners(AuditingEntityListener.class) @MappedSuperclass public class BaseEntity { @CreatedDate @Column(updatable = false) protected LocalDateTime createdAt; @CreatedBy @Column(updatable = false) private String createdBy; @LastModifiedDate // 移除updatable=false,默认即为可更新 protected LocalDateTime updatedAt; @LastModifiedBy // 移除updatable=false,默认即为可更新 protected String updatedBy; }
2. 核对数据库表字段映射
检查数据库表t_spotify_playlist是否包含created_at、created_by、updated_at、updated_by四个字段,字段类型是否与实体类匹配(比如LocalDateTime对应数据库的datetime/timestamp类型)。缺少字段需同步创建。
3. 确认save方法触发JPA更新逻辑
如果使用Spring Data JPA的默认save()方法,从数据库查询出的持久化实体调用save会自动触发更新;如果是自定义save方法,需确保调用了entityManager.merge()(更新现有实体)或entityManager.persist()(新增实体),否则审计逻辑不会被触发。
4. 验证审计监听器是否生效
在AuditorAwareImpl的getCurrentAuditor()方法中添加日志,确认该方法是否被调用:
@Component("auditorAwareImpl") public class AuditorAwareImpl implements AuditorAware<String> { private static final Logger log = LoggerFactory.getLogger(AuditorAwareImpl.class); @NotNull @Override public Optional<String> getCurrentAuditor() { log.info("触发审计用户获取逻辑"); return Optional.of("system"); } }
如果日志未打印,需检查@EnableJpaAuditing是否配置正确,AuditorAwareImpl是否被Spring容器扫描加载。
5. 排查版本兼容性问题
确保Spring Boot、Spring Data JPA、Hibernate版本相互兼容,版本冲突可能导致审计注解失效。
内容的提问来源于stack exchange,提问作者Nunyet Calçada

