首先,我没有考虑记录的主要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应该是完全随机生成的,或者是根据名称做的。应该怎么做?
我知道如果不锁定整个表格,就不可能确保插入不会因为违反唯一性限制而导致异常。我实际上可以阻止整个表,甚至让异常发生(在检查可用性和插入之间发生冲突时,每秒需要大量请求)。
答案 0 :(得分:1)
如果你将slug与Account
表分开并将它自己放在(id, slug)
表中,你可以先生成slug(重试直到你成功),然后保持{{1}带有刚刚生成的slug id的链接。
您无法通过Account
方法实现此目的,因此,只要您创建新的@PrePersist
,您的服务就需要创建slu ..但是它确实简化了应用程序方面的事情(例如,在持久化Account
时,您不需要知道违反了哪个约束。)
根据您的其他代码,如果您采用乐观方法,您还可以绕过Account
表甚至Account
表。
创建新帐户的服务方法的伪代码示例(提供Slug
会创建随机slug):
new Slug()
答案 1 :(得分:0)
我可以想到JPA callbacks来生成slu ..在您的情况下,@PrePersist
可能很有用。
那就是说,为什么在插入记录之前需要确保值是可用的,所以发生碰撞的窗口很小?你对列有唯一约束,对吧?
<强>更新强>
就我个人而言,我更愿意这样解决:
@PrePersist
。用于随机UUID或时间戳以最小化冲突的可能性。没有检查碰撞,因为机会很小。Account
时,请务必首先使用查询进行冲突检查。此检查将在服务更新方法本身中发生。 这样我就可以与数据库无关,也不必在实体或监听器类中使用存储库/服务。
答案 2 :(得分:0)
我将做类似这样的单独的Bean,帮助程序或服务类。
public class SlugService {
public String generateSlug(String slug)
{
if (accountRepo.getBySlug(slug) != null){ //check if it is already
return slug
} else {
slug.append("-"); //whatever the syntax
generateSlug();
}
}
public String makeSlug()
{
String slug = split by " ", replace by "_"(accountObject.getName);
generateSlug(slug)
}
}
调用makeSlug();方法。