所以我正在开发一个Java项目,但实际上这里的语言无关紧要。
所以我想在数据存储区中创建和存储用户,并且我正在努力找到最好的方法,这样我就可以确保不会多次使用电子邮件。因此,在关系ACID数据库上执行此操作的常规方法是在事务期间。 锁定数据库,查看电子邮件是否存在,是否存在,然后解锁并失败,否则插入和解锁。
现在这个概念可以在Appengine中使用,也可以使用事务。但是,由于该条目可能仅在几毫秒之前插入,因此可能不会出现在数据存储区中,因为它具有强大/最终的一致性。
所以我想过的事情:
为所有用户使用全局父级,以便我可以在事务中执行祖先查询,从而强制它成为查询的最新数据。但是,这会导致每秒1 XG更新限制的问题。 (这是我决定不采用的方法)
将插入到内存缓存中的电子邮件存储在一个单独的列表中,因为即使它被清除,它也可能在条目插入数据存储区之前无法清除,因此我们可以搜索缓存和数据存储区,如果它们都不存在,我们可以假设它不会出现在数据存储区中。但是,此memcache查找不会成为事务的一部分,因此仍然存在问题
所以我的主要问题是这些方法都不会使用祖先查询,因此不能作为事务的一部分来完成。
由于
编辑: 在考虑结构后,我正在考虑这样的事情。我将在以后回家时进行测试,并将其作为我接受的答案标记,如果有效的话。
UserBean
@id Long id;
//All child elements will use UserBean as their parent
Login
@id String id; //This will be the a hashed/base64 version of the email address
@Parent UserBean user;
String emailAddress
String hashedPassword;
start transaction
Login login = ofy()
.load()
.type(Login.class)
.key(hashEmail(emailAddress)).now();
if (login == null) {
fail transaction - email already in use
}
Insert UserBean and Login objects into datastore
答案 0 :(得分:0)
我使用App Engine的Python风格,但我怀疑Java中有类似的功能。
您可以执行以下操作:
key_name
和get_or_insert(key_name)
(docs)。通过使用get_or_insert
,您可以保证不会多次创建同一个实体。
答案 1 :(得分:0)
所以我有一个有效的解决方案,我很乐意在这里分享。
我的两个POJO:
@Entity
public class UserAccount {
@Id Long _id;
public UserAccount(){
}
public Long get_id() {
return _id;
}
}
@Entity
public class LoginBean {
@Id String emailHash;
//I don't make this an actual @Parent because this would affect the Id
Ref<UserAccount> parent;
String email;
String hashedPassword;
public LoginBean(){
}
public LoginBean(String emailHash, Ref<UserAccount> parent, String email, String hashedPassword){
this.parent = parent;
this.emailHash = emailHash;
this.email = email;
this.hashedPassword = hashedPassword;
}
//All the rest of the getters and setters you want
}
然后在我的实用程序类中:
final String emailHash = getEmailHash(email);
final String passwordHash = getPasswordHash(password);
UserAccount savedUser = ofy().transact(new Work<UserAccount>() {
public UserAccount run() {
if (lookupByEmail(email) != null) {
return null;
}
UserAccount user = new UserAccount();
Key<UserAccount> userKey = ofy().save().entity(user).now();
LoginBean login = new LoginBean(emailHash, Ref.create(userKey), email, passwordHash);
ofy().save().entity(login).now();
return user;
}
});
进一步向下:
public LoginBean lookupByEmail(String email) {
String emailhash = getEmailHash(email);
LoginBean r = ofy().load().type(LoginBean .class).id(emailhash).now();
return r;
}