我正在使用对象化。比如说,我有一个 User
类型,它具有 name
和 email
属性。实现注册时,我想检查是否已注册具有相同名称 或 相同电子邮件的用户。因为可以从许多来源调用注册,所以可能会出现竞争条件。
为了防止竞争条件,一切都必须以某种方式包装在事务中。如何消除竞争条件?
GAE 文档解释了如何在实体不存在的情况下创建实体,但它们假设 ID 已知。因为,我需要检查两个无法指定 ID 的属性。
最佳答案
受@konqi 回答的启发,我想出了一个类似的解决方案。
想法是创建User_Name
和 User_Email
将保留迄今为止创建的所有用户的姓名和电子邮件的实体。不会有父子关系。为了方便起见,我们也将保留用户的姓名和电子邮件属性;我们正在用存储换取更少的读/写。
@Entity
public class User {
@Id public Long id;
@Index public String name;
@Index public String email;
// other properties...
}
@Entity
public class User_Name {
private User_Name() {
}
public User_Name(String name) {
this.name = name;
}
@Id public String name;
}
@Entity
public class User_Email {
private User_Email() {
}
public User_Email(String email) {
this.email = email;
}
@Id public String email;
}
现在通过检查唯一字段在交易中创建用户:
User user = ofy().transact(new Work<User>() {
@Override
public User run()
{
User_Name name = ofy().load().key(Key.create(User_Name.class, data.username)).now();
if (name != null)
return null;
User_Email email = ofy().load().key(Key.create(User_Email.class, data.email)).now();
if (email != null)
return null;
name = new User_Name(data.username);
email = new User_Email(data.email);
ofy().save().entity(name).now();
ofy().save().entity(email).now();
// only if email and name is unique create the user
User user = new User();
user.name = data.username;
user.email = data.email;
// fill other properties...
ofy().save().entity(user).now();
return user;
}
});
这将保证这些属性的唯一性(至少我的测试凭经验证明了这一点 :))。并且不使用 Ref<?>
s 我们保持数据紧凑,这将减少查询。
如果只有一个独特的属性,最好将其设为 @Id
主体。
也可以设置 @Id
用户的电子邮件或姓名,并将新种类的数量减少一个。但我认为为每个独特的属性创建一个新的实体类型会使意图(和代码)更加清晰。
关于java - 如何在交易中创建具有独特属性的实体?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33290013/