複数のユーザーが同時にアカウントを作成する 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 ユーザーからキーを取得し、それを上記のコードのクエリの祖先キーにします。それもうまくいきませんでした。今でも重複した電子メール アドレスを取得しています。また、グループ間トランザクションになるようにトランザクションを構成しようとしましたが、それも役に立ちませんでした。
それで、これを機能させる方法に関するヒントはありますか?それはまったく可能ですか?