Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/css/38.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Google app engine 将用户存储在具有唯一电子邮件地址的数据存储中_Google App Engine_Objectify_Google Cloud Datastore - Fatal编程技术网

Google app engine 将用户存储在具有唯一电子邮件地址的数据存储中

Google app engine 将用户存储在具有唯一电子邮件地址的数据存储中,google-app-engine,objectify,google-cloud-datastore,Google App Engine,Objectify,Google Cloud Datastore,所以我在用Java做一个项目,但实际上语言在这里并不重要 因此,我想在数据存储中创建和存储用户,我正在努力找出最好的方法,这样我就可以确保电子邮件不会被多次使用。因此,在关系型ACID数据库上执行此操作的正常方式是在事务期间。 锁定数据库,查找电子邮件是否存在,如果存在,则解锁并失败,否则插入并解锁 现在,这一概念将在Appengine中起作用,您也可以使用事务。但是,由于条目可能仅在毫秒之前插入,因此由于强一致性/最终一致性,它可能尚未出现在数据存储中 所以我想的是: 为所有用户使用全局父级

所以我在用Java做一个项目,但实际上语言在这里并不重要

因此,我想在数据存储中创建和存储用户,我正在努力找出最好的方法,这样我就可以确保电子邮件不会被多次使用。因此,在关系型ACID数据库上执行此操作的正常方式是在事务期间。 锁定数据库,查找电子邮件是否存在,如果存在,则解锁并失败,否则插入并解锁

现在,这一概念将在Appengine中起作用,您也可以使用事务。但是,由于条目可能仅在毫秒之前插入,因此由于强一致性/最终一致性,它可能尚未出现在数据存储中

所以我想的是:

  • 为所有用户使用全局父级,这样我就可以在事务中执行祖先查询,从而强制它成为查询的最新数据。但是,这会导致每秒更新1次XG的限制出现问题。(这是我决定不采用的方法)

  • 将插入memcache的电子邮件存储在一个单独的列表中,因为即使它被清除,在条目插入数据存储之前它也可能不会被清除,因此我们可以搜索缓存和数据存储,如果它不在其中,我们可以假设它不在数据存储中。但是,此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

我使用的是appengine的Python风格,但我怀疑Java中也有类似的功能

您可以执行以下操作:

  • 使用电子邮件地址作为实体的
    关键字名称
    ,以及
  • 使用
    get\u或\u insert(key\u name)
    ()创建实体

  • 通过使用
    get\u或\u insert
    可以保证不会多次创建同一个实体。

    我使用的是App Engine的Python风格,但我怀疑Java中也有类似的功能

    您可以执行以下操作:

  • 使用电子邮件地址作为实体的
    关键字名称
    ,以及
  • 使用
    get\u或\u insert(key\u name)
    ()创建实体

  • 通过使用
    get\u或\u insert
    可以保证不会多次创建同一实体。

    因此,我有一个工作解决方案,我很乐意在这里分享

    我的两个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
    }
    

    因此,我有一个有效的解决方案,我很乐意在这里分享

    我的两个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
    }
    

    心想#1:因为你叫它名字的原因,这确实是个坏主意。思考2:不管memcache在错误/正确的时刻被逐出的可能性有多大,如果它被逐出,s***真的会让粉丝们大吃一惊。所以,不要做出通常情况下的假设,一个不寻常的情况将打破你的脖子。我的想法:您是否考虑过创建一个表,其中电子邮件是
    @Id
    ?如果我直截了当地了解了事实,那么按id进行的查询总是非常一致的。但它们不能在事务中完成,除非我有一个子实体也有电子邮件,然后我可以执行祖先查询以验证子元素是否存在。但是如果用户想要更改他们的电子邮件地址,这确实会导致大量的数据库操作,因为这会要求所有子元素随着父id的更改而更新,不是吗?看看我们使用的“唯一”用户名,但这种方法也适用于电子邮件。我在我的原始帖子中添加了一个编辑,其中包含了我正在考虑的对象的初步设计。如果@id是电子邮件,那么您可以在交易中使用此单一实体。按键获取,如果不存在,则放入。思想#1:因为你命名的原因,这确实是个坏主意。思考2:不管memcache在错误/正确的时刻被逐出的可能性有多大,如果它被逐出,s***真的会让粉丝们大吃一惊。所以,不要做出通常情况下的假设,一个不寻常的情况将打破你的脖子。我的想法:您是否考虑过创建一个表,其中电子邮件是
    @Id
    ?如果我直截了当地了解了事实,那么按id进行的查询总是非常一致的。但它们不能在事务中完成,除非我有一个子实体也有电子邮件,然后我可以执行祖先查询以验证子元素是否存在。但是如果用户想要更改他们的电子邮件地址,这确实会导致大量的数据库操作,因为这会要求所有子元素随着父id的更改而更新,不是吗?看看我们使用的“唯一”用户名,但这种方法也适用于电子邮件。我在我的原始帖子中添加了一个编辑,其中包含了我正在考虑的对象的初步设计。如果@id是电子邮件,那么您可以在交易中使用此单一实体。按钥匙取,如果不存在就放。遗憾的是,你的怀疑是错误的。在Java中,您必须自己实现
    get\u或\u insert
    的功能。但是get\u或\u insert的问题是,它并不能真正说明它执行了哪个操作。您必须检查返回的实体是否被找到,并且在创建新记录之前可能需要执行其他验证。@TimHoffman,是的,这是对的,但这似乎不是一个明显的限制。假设,在创建实体后,您将设置至少一个属性,您只需检查该属性是否已设置。遗憾的是,您的怀疑是错误的。在Java中,您必须自己实现
    get\u或\u insert
    的功能。但是get\u或\u insert的问题是,它并不能真正说明它执行了哪个操作。您必须检查返回的实体是否已找到,并且可能需要进行其他验证
    public LoginBean lookupByEmail(String email) {
        String emailhash = getEmailHash(email);
        LoginBean r = ofy().load().type(LoginBean .class).id(emailhash).now();
        return r;
    }