【问题标题】:Neo4j SDN4 and a correct usage of internal IdsNeo4j SDN4 和内部 ID 的正确使用
【发布时间】:2017-02-13 19:11:01
【问题描述】:

我读到将 Neo4j 内部 ID 用于外部目的不是一个好习惯。

我认为我在我的 SDN4/Neo4j 应用程序中犯了一个错误,因为我到处都在使用内部 ID。

我的应用程序中的每个 SDN 4 节点实体都有以下属性:

@GraphId
private Long id;

我将这个长值用作我的 Web 应用程序 URL 的一部分。例如

/products/3245234

其中3245234 是此产品节点实体的内部 Neo4j 标识符。

从 Neo4j 的角度来看,以这种方式使用内部 ID 是否安全?如果不是,您能否举例说明新代理键如何解决此问题。

【问题讨论】:

    标签: neo4j spring-data-neo4j-4 neo4j-ogm


    【解决方案1】:

    在谈到 Neo4j 内部 ID 如何被回收时,Eric 所说的是正确的。

    我们已开始添加对 SDN 的支持,以帮助开发人员解决此问题。我们可以通过几个例子来做到这一点。

    示例 1:当您拥有自然 ID 时

    假设我们有一个User 域对象,它可以由一个名为email 的字段唯一标识。我们可以这样设置我们的模型:

    @NodeEntity
    public class User {
    
        @GraphId
        private Long id;
    
        @Index(unique=true, primary=true)
        private String email;
    
        ... 
    
    }
    

    然后我们可以这样设置一个存储库:

    public interface UserRepository extends CrudRepository<User, String> {
    
    }
    

    注意参数化类型中的最后一个值是字符串。这表示用于此类的主索引。

    您现在可以执行以下操作:

    User user = userRepository.findOne("john.doe@email.com");
    

    看看如何只为类传递主 ID?

    示例 2:当您需要合成 ID 时

    假设我们上面定义的用户有推文。由于推文没有自然 ID,我们给它一个。避免 ID 冲突的最佳方法是使用 4 类 UUID。幸运的是,Java 预装了 UUID,SDN 支持它的持久化。

    import org.neo4j.ogm.annotation.typeconversion.Convert;
    import org.neo4j.ogm.typeconversion.UuidStringConverter;
    import java.util.UUID;
    
    @NodeEntity
    public class Tweet {
    
        @GraphId
        private Long id;
    
        @Convert(UuidStringConverter.class)
        @Index(unique = true, primary = true)
        private UUID uuid;
    
        ...
    
        public Tweet(String message) {
            this.uuid = UUID.randomUUID();
            // other initialisation.
        }
    }
    

    所以我们这里有一个UUID 分配给任何创建的推文。然后可以通过转换器将其保存到数据库中。这样做的方便之处在于无需安装额外的库。它也保证(嗯,在大多数情况下!)永远不会有内部 Neo4j ID 的问题。优点(或缺点)是 ID 被制造为由您的应用程序代码普遍唯一。

    如果您希望数据库始终生成 UUID,那么我还推荐 GraphAware https://github.com/graphaware/neo4j-uuid 插件。

    Tweet 存储库再次可以利用这一点:

    public interface TweetRepository extends CrudRepository<Tweet, UUID> {
    
    }
    

    您现在可以执行以下操作:

    Tweet tweet = tweetRepository.findOne(UUID.fromString("0f6e7004-cefc-4397-b4d2-078c1370856a"));
    

    最后一点;在撰写本文时,@Indexed(unique=true,primary=true) 可能会在 SDN 5.0 中更改为简单地称为 @Id

    【讨论】:

    • 非常感谢您的详细解答!关于 Cypher 查询和UUID 的一个后续问题。以前作为我的 Cypher 查询的参数,我使用了Ids(@GraphId) 和以下语句 - 例如 WHERE ID(p) in {productIds}.. 现在我必须传递一组 UUID 而不是内部 ID。如何在 Cypher 中正确使用这些 UUID - ID(p) IN {productUUIDs} 或 simlpe p IN {productUUIDs}。另外,从性能的角度来看,GraphId@Index(unique = true, primary = true) private UUID uuid 之间有什么区别吗?
    • 您应该能够执行WHERE p.uuid IN {productUuids} 之类的操作,其中productUuids 是字符串表示形式。我不确定我们目前是否支持存储库方法的参数转换,但我们将在下一个版本中支持。关于性能,如果您打开自动索引或者您已经对该标签的 uuid 属性进行了索引,那么它应该非常快,因为查找是通过索引完成的。
    【解决方案2】:

    从应用程序的角度来看,使用 Neo4j 内部 id 是安全的,因为使用它们不会破坏应用程序中的任何内容。

    也就是说,Neo4j 内部 id 被回收,我的意思是如果一个节点或关系的内部 id 为 12345,并且在某个时候该节点或关系被删除,则 12345 的 id 将有资格被未来的节点重用或关系。我相信假设新可用的 id 将在将来的某个时候重用是明智的。这具有负面影响,即 Neo4j 内部 id 不被认为是“稳定的”,不应在您的应用程序之外使用。

    至于新代理键的示例,我将向您介绍 GraphAware 的 neo4j-uuid 项目https://github.com/graphaware/neo4j-uuid。这个 Neo4j 插件可用于在所有节点和关系上自动创建唯一且稳定的 UUID,不会也不能更改或更新。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多