java使用Spring Boot/JPA生成唯一字段的正确方法是什么?
首先,我没有考虑记录的主要id。我说的是一个字段,用户使用该字段来标识用户自动生成但可更改的记录,它不是顺序的,也不是UUID。例如,从帐户实体开始:
@Entity
@Data
class Account {
@Id
@GeneratedValue
private int id;
@Column(unique=true)
@NotNull
private String slug;
@Column
private String name;
}
然后我简单地创建一个记录:
@Autowired
private AccountRepository accountRepository;
Account account = new Account();
account.setName("ACME");
accountRepository.saveAndFlush(account);
此时,slug应该已经生成,要么完全随机生成,要么根据名称执行某些操作。应该怎样做呢
我知道,如果不锁定整个表,就不可能确保插入不会由于违反唯一性约束而导致异常。实际上,我可以阻塞整个表,甚至允许异常发生(在检查可用性和插入之间发生冲突时,每秒需要大量请求)
# 1 楼答案
我会像这样做一个单独的Bean、助手或服务类
调用makeSlug();方法
# 2 楼答案
我可以想出JPA callbacks来生成slug。在你的情况下
@PrePersist
可能有用也就是说,为什么在插入记录之前需要确保select可以使用该值,所以发生冲突的窗口很小?柱上有唯一的约束,对吗
更新
就我个人而言,我更愿意这样说:
@PrePersist
。使用随机UUID或时间戳来最小化冲突的可能性。没有检查碰撞的可能性很小李>Account
时,请始终首先使用query for collision进行检查。这种检查当然会发生在服务更新方法本身中李>这样我就可以不依赖数据库,也不必在实体或侦听器类中使用存储库/服务
# 3 楼答案
如果将slug从
Account
表中分离出来,并将其单独放入(id, slug)
表中,则可以先生成slug(重试直到成功),然后通过指向刚生成的slug id的链接持久化Account
在
@PrePersist
方法中无法实现这一点,因此每当您创建新的Account
时,您的服务都需要创建slug。然而,它确实简化了应用程序方面的事情(例如,在持久化Account
时,您不需要怀疑违反了哪个约束)根据其他代码的不同,如果采用乐观的方法,还可以绕过锁定
Account
表,甚至锁定Slug
表创建新帐户的服务方法的伪代码示例(提供
new Slug()
创建随机slug):