我有一个Spring Boot应用程序,它具有简单的Entity以及JpaRepository和Service。
实体:
@Getter
@Setter
@EntityListeners(AuditingEntityListener.class)
public class User {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private Long id;
@Version
private Long version;
@CreatedDate
private LocalDateTime created;
@LastModifiedDate
private LocalDateTime lastModified;
@CreatedBy
private String createdBy;
@LastModifiedBy
private String lastModifiedBy;
private String name;
private String email;
}
JpaRepository :
@Repository
public interface UserRepository extends JpaRepository<User, Long> {}
服务:
@Service
class UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public User create(User user) {
Assert.isNull(user.getId(), "Can't create an existing user!");
return userRepository.saveAndFlush(user);
}
@Transactional
public User update(User user) {
Assert.notNull(user.getId(), "Can't update a new user!");
return userRepository.saveAndFlush(user);
}
}
在我的实际应用程序中,
@Transactional
中设置了RestController
批注,但是create()
和update()
从未在同一事务中执行
当我这样创建新用户时:
User user = new User();
user.setName("user");
user.setEmail("user@email");
userService.create(user);
Spring会自动将所有Auditing属性(创建,lastModified等)设置为0。
但是当我像这样更新现有用户时:
User user = new User();
user.setId(1L); // Id of the User I want to update
user.setVersion(5L) // Current version is 5L
user.setName("user");
user.setEmail("new@email"); // I want to update only the email
userService.update(user);
我收到此错误:
org.postgresql.util.PSQLException: ERROR: null value in column "created" violates not-null constraint
这意味着Spring审核未处理created
属性。
要解决此问题,我已通过以下方式在update
中更改了UserService
方法:
@Transactional
public User update(User user) {
Assert.notNull(user.getId(), "Can't update a new user!");
User original = userRepository.getOne(user.getId())
original.setVersion(user.getVersion());
original.setName(user.getName());
original.setEmail(user.getEmail());
return userRepository.saveAndFlush(original);
}
此命令修复了PSQLException
,但是此版本不再经过验证。这意味着,如果我在数据库中设置的版本与当前版本不同,则不会出现ObjectOptimisticLockingFailureException
错误,并且更新后的用户将被保存在数据库中而没有任何错误。
我可以将
.getOne()
替换为.findById()
,但没有任何变化
最后,我已经能够以这种方式解决我的两个问题:
@Transactional
public User update(User user) {
Assert.notNull(user.getId(), "Can't update a new user!");
Assert.notNull(user.getVersion(), "Version must be defined!");
User original = userRepository.getOne(user.getId())
User update = new User();
update.setId(original.getId());
update.setCreated(original.getCreated());
update.setCreatedBy(original.getCreatedBy());
update.setVersion(user.getVersion());
update.setName(user.getName());
update.setEmail(user.getEmail());
return userRepository.saveAndFlush(update);
}
我仍然需要检查版本是否为null,否则用户将被保存而不检查版本
现在,审核字段不会抛出PSQLException
,并且版本会在更新之前进行验证,并且在错误时会抛出ObjectOptimisticLockingFailureException
。
但是此解决方案糟糕,因为我需要左右复制属性,在较大的实体中,很容易忘记某些东西。
您知道此问题的更好解决方案吗?