JPA中@LastModifiedDate同事务更新后返回旧值问题求助
JPA同一事务内更新实体后@LastModifiedDate返回旧值问题
在同一事务内更新User实体后再次查询,实体的普通修改字段(如username、email)能正常返回新值,但父类BaseEntity中用@LastModifiedDate标注的updatedAt字段仍显示更新前的旧值。已确认数据库中该字段已正确更新,推测是JPA缓存机制导致,但无法解决。
环境信息
- Java版本:17
- Spring Boot版本:3.0.3
- 数据库:PostgreSQL
实体代码
User 实体
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; import lombok.ToString; import org.hibernate.annotations.DynamicUpdate; import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.Where; import java.io.Serial; import java.time.LocalDateTime; import java.util.LinkedHashSet; import java.util.Set; @Getter @Setter @ToString(callSuper = true) @Entity @Table(name = User.TABLE_NAME, uniqueConstraints = { @UniqueConstraint( name = User.UNIQUE_KEY_EMAIL_DELETED, columnNames = {User.COLUMN_EMAIL_NAME, BaseEntity.COLUMN_DELETED_NAME}), @UniqueConstraint( name = User.UNIQUE_KEY_USERNAME_DELETED, columnNames = {User.COLUMN_USERNAME_NAME, BaseEntity.COLUMN_DELETED_NAME} ) }) @SQLDelete(sql = BaseEntity.DELETE_SQL_PREFIX + User.TABLE_NAME + BaseEntity.DELETE_SQL_SUFFIX) @Where(clause = BaseEntity.WHERE_DELETED_SQL) @DynamicUpdate public class User extends BaseEntity { public static final String TABLE_NAME = "sys_user"; @Serial private static final long serialVersionUID = 2788923386294327164L; public static final String COLUMN_USERNAME_NAME = "username"; public static final String COLUMN_EMAIL_NAME = "email"; public static final String UNIQUE_KEY_EMAIL_DELETED = "uni_email_deleted"; public static final String COLUMN_EXPIRED_TIME_NAME = "expired_time"; public static final String COLUMN_IS_LOCKED_NAME = "locked"; public static final String COLUMN_IS_ENABLED_NAME = "enabled"; public static final String UNIQUE_KEY_USERNAME_DELETED = "uni_username_deleted"; @Column(name = COLUMN_USERNAME_NAME, nullable = false) private String username; @Column(name = COLUMN_EMAIL_NAME, nullable = false) private String email; @Column(name = COLUMN_EXPIRED_TIME_NAME) private LocalDateTime expiredTime; @Column(name = COLUMN_IS_LOCKED_NAME, nullable = false) private Boolean locked = false; @Column(name = COLUMN_IS_ENABLED_NAME, nullable = false) private Boolean enabled = false; @ToString.Exclude @OneToOne(mappedBy = UserPassword.JOIN_COLUMN_USER_MAPPED_NAME, orphanRemoval = true, cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @JsonIgnoreProperties(UserPassword.JOIN_COLUMN_USER_MAPPED_NAME) private UserPassword userPassword; @ToString.Exclude @OneToMany(mappedBy = UserToRole.JOIN_COLUMN_USER_MAPPED_NAME, orphanRemoval = true, cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @JsonIgnoreProperties(UserToRole.JOIN_COLUMN_USER_MAPPED_NAME) private Set<UserToRole> userToRoles = new LinkedHashSet<>(); }
BaseEntity 父类
import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; import lombok.ToString; import org.hibernate.Hibernate; import org.springframework.data.annotation.CreatedBy; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedBy; import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; import java.io.Serial; import java.io.Serializable; import java.time.LocalDateTime; import java.util.Objects; @Getter @Setter @ToString @MappedSuperclass @EntityListeners(AuditingEntityListener.class) public class BaseEntity implements Serializable { public static final String COLUMN_ID_NAME = "id"; @Serial private static final long serialVersionUID = 9146658035652051074L; public static final String COLUMN_CREATED_AT_NAME = "created_at"; public static final String COLUMN_UPDATED_AT_NAME = "updated_at"; public static final String COLUMN_VERSION_NAME = "version"; public static final String COLUMN_DELETED_NAME = "deleted"; public static final String WHERE_DELETED_SQL = "deleted=-1"; public static final String DELETE_SQL_PREFIX = "UPDATE "; public static final String DELETE_SQL_SUFFIX = " SET deleted = id WHERE id=? and version=? and system_created=false"; public static final String COLUMN_SYSTEM_CREATED_NAME = "system_created"; public static final String COLUMN_CREATED_BY_NAME = "created_by"; public static final String COLUMN_UPDATED_BY_NAME = "updated_by"; @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = COLUMN_ID_NAME, nullable = false) private Long id; @CreatedDate @Column(name = COLUMN_CREATED_AT_NAME, nullable = false, updatable = false) private LocalDateTime createdAt; @LastModifiedDate @Column(name = COLUMN_UPDATED_AT_NAME, nullable = false) private LocalDateTime updatedAt; @Version @Column(name = COLUMN_VERSION_NAME, nullable = false) private Integer version; @Column(name = COLUMN_DELETED_NAME, nullable = false) private Long deleted = -1L; @Column(name = COLUMN_SYSTEM_CREATED_NAME, nullable = false) private boolean systemCreated = false; @CreatedBy @Column(name = COLUMN_CREATED_BY_NAME, nullable = false, updatable = false) private Long createdBy; @LastModifiedBy @Column(name = COLUMN_UPDATED_BY_NAME, nullable = false) private Long updatedBy; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false; BaseEntity that = (BaseEntity) o; return id != null && Objects.equals(id, that.id); } @Override public int hashCode() { return getClass().hashCode(); } }
服务层代码
@Transactional @Override public UserInfoDto updateUser(UserUpdateQuery userUpdateQuery) { return userMapper.toDto(this.userDo(userUpdateQuery.getId(), user -> { if (StringUtils.hasText(userUpdateQuery.getUsername())) { user.setUsername(userUpdateQuery.getUsername()); } if (StringUtils.hasText(userUpdateQuery.getEmail())) { user.setEmail(userUpdateQuery.getEmail()); } return userRepository.findById(user.getId()).orElseThrow(() -> new RuntimeException()); })); } protected <R> R userDo(Long id, Function<User, R> function) { Optional<User> userOptional = userRepository.findById(id); User user = userOptional.orElseThrow(() -> new DataNotExistException("exception.admin.user_not_exist")); return function.apply(user); }
仓库层代码
public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User>, PagingAndSortingRepository<User, Long> { <T> Optional<T> findUserById(Long id, Class<T> type); <T> Optional<T> findUserByUsername(String username, Class<T> type); <T> Optional<T> findUserByEmail(String email, Class<T> type); }
已尝试方案与需求
已尝试调用userRepository.save()和flush()方法,均无法解决问题。需求是在同一事务内更新实体后,能够获取到正确的@LastModifiedDate字段值。
内容的提问来源于stack exchange,提问作者Lyle
相关产品推荐
相关产品推荐

