考虑一个基于Web的系统,其中多个用户可能同时创建帐户。系统要求用户具有唯一的用户名以及唯一的电子邮件地址。在RDBMS中,这很简单:“email”字段将标记为UNIQUE。我怎样才能以数据存储的方式处理这个问题?
这是我最初的尝试:
// Create entity using the username as key
String username = ... // provided by the user
String email = ... // provided by the user
Entity entity = new Entity("Users", KeyFactory.createKey("User", username));
entity.setProperty("email", email);
// Create a query that matches the email property
Query q = new Query();
q.setFilter(new FilterPredicate("email", FilterOperator.EQUAL, email));
// Start a transaction
Transaction txn = datastore.beginTransaction();
try {
// Try to get an entity with that username
datastore.get(KeyFactory.createKey("User", username);
}
catch(EntityNotFoundException e) {
// No entity with that username, make sure the e-mail
// is not taken either
PreparedQuery pq = datastore.prepare(q);
if (pq.countEntities(FetchOptions.Builder.withLimit(1)) == 0) {
// The e-mail isn't taken either, all good
datastore.put(entity);
txn.commit();
... handle success here ...
return;
}
}
finally {
if (txn.isActive())
txn.rollback();
}
... handle failure here ...
但经过一些简单的测试后,我注意到查询并不总是“看到”之前很短时间内的“看跌”(最终的一致性,我应该猜到)。为了解决这个问题,我尝试将该查询转换为“虚拟”祖先查询。
所以这个“虚拟”祖先查询就是这样的。我创建了一个具有命名键的RootUser实体。我从这个root用户那里获得了密钥,并将其作为上述代码中查询的祖先密钥。既然这也不起作用,我仍然会收到重复的电子邮件地址。我还尝试配置事务,因此它是一个跨组事务,但这也无济于事。
那么,关于如何使这个工作的任何提示?它有可能吗?
答案 0 :(得分:2)
快速版:您希望使用另一个实体“kind”并将您的唯一值存储为此类对象的ID。例如。 “User.username:myusername”,“User.email:email@example.com”。通过首先创建这些条目,您将知道值何时不唯一。
请参阅此示例实现.. http://webapp-improved.appspot.com/_modules/webapp2_extras/appengine/auth/models.html#Unique