处理和供应唯一 ID
使用内部 Neo4j ID
为域类提供唯一标识符的最简单方法是在 or 类型的字段上组合 and(最好是对象,而不是标量,因为 literals 是更好的指示实例是否为新实例):@Id
@GeneratedValue
String
Long
long
null
@Node("Movie")
public class MovieEntity {
@Id @GeneratedValue
private Long id;
private String name;
public MovieEntity(String name) {
this.name = name;
}
}
您无需为字段提供 setter,SDN 将使用反射来分配字段,但如果有 setter,则使用 setter。 如果要创建具有内部生成的 id 的不可变实体,则必须提供 wither。
@Node("Movie")
public class MovieEntity {
@Id @GeneratedValue
private final Long id; (1)
private String name;
public MovieEntity(String name) { (2)
this(null, name);
}
private MovieEntity(Long id, String name) { (3)
this.id = id;
this.name = name;
}
public MovieEntity withId(Long id) { (4)
if (this.id.equals(id)) {
return this;
} else {
return new MovieEntity(id, this.title);
}
}
}
1 | 指示生成值的不可变最终 ID 字段 |
2 | 应用程序和 Spring Data 使用的公共构造函数 |
3 | 内部使用的构造函数 |
4 | 这就是所谓的 -attribute 的 wither。
它创建一个新实体并相应地设置字段,而无需修改原始实体,从而使其不可变。id |
如果你想让
-
优点: 很明显,id 属性是代理业务密钥,使用它不需要进一步的努力或配置。
-
缺点:它与 Neo4js 内部数据库 ID 相关联,这并不是我们的应用程序实体仅在数据库生命周期内唯一的唯一。
-
缺点:创建不可变实体需要花费更多精力
使用外部提供的代理键
注解可以采用一个类 implementation 作为参数。
SDN 提供 (默认) 和开箱即用。
后者为每个实体生成新的 UUID,并将其作为 .
使用该 API 的应用程序实体将如下所示:@GeneratedValue
org.springframework.data.neo4j.core.schema.IdGenerator
InternalIdGenerator
UUIDStringGenerator
java.lang.String
@Node("Movie")
public class MovieEntity {
@Id @GeneratedValue(UUIDStringGenerator.class)
private String id;
private String name;
}
关于优点和缺点,我们必须讨论两件不同的事情。 赋值本身和 UUID-Strategy. 通用唯一标识符在实际应用中是唯一的。 引用维基百科: “因此,任何人都可以创建一个 UUID 并使用它来识别某些东西,几乎可以肯定该标识符不会与已经或将要创建的标识符重复以识别其他东西。”我们的策略使用 Java 内部 UUID 机制,采用密码学强的伪随机数生成器。 在大多数情况下,这应该可以正常工作,但您的里程可能会有所不同。
这就剩下了赋值本身:
-
优点:应用程序处于完全控制之中,并且可以生成一个唯一密钥,该密钥对于应用程序的目的来说足够唯一。 生成的值将是稳定的,以后不需要更改它。
-
缺点:生成的策略应用于 Thing 的应用程序端。 在那些日子里,大多数应用程序将部署在多个实例中,以便很好地扩展。 如果您的策略容易生成重复项,则插入将失败,因为将违反主键的唯一性属性。 因此,虽然在这种情况下您不必考虑唯一的业务密钥,但您必须更多地考虑要生成什么。
您可以通过多种方式推出自己的 ID 生成器。 一个是实现生成器的 POJO:
import java.util.concurrent.atomic.AtomicInteger;
import org.springframework.data.neo4j.core.schema.IdGenerator;
import org.springframework.util.StringUtils;
public class TestSequenceGenerator implements IdGenerator<String> {
private final AtomicInteger sequence = new AtomicInteger(0);
@Override
public String generateId(String primaryLabel, Object entity) {
return StringUtils.uncapitalize(primaryLabel) +
"-" + sequence.incrementAndGet();
}
}
另一种选择是提供额外的 Spring Bean,如下所示:
@Component
class MyIdGenerator implements IdGenerator<String> {
private final Neo4jClient neo4jClient;
public MyIdGenerator(Neo4jClient neo4jClient) {
this.neo4jClient = neo4jClient;
}
@Override
public String generateId(String primaryLabel, Object entity) {
return neo4jClient.query("YOUR CYPHER QUERY FOR THE NEXT ID") (1)
.fetchAs(String.class).one().get();
}
}
1 | 请准确使用您需要的 query 或 logic。 |
上面的生成器将被配置为 bean 引用,如下所示:
@Node("Movie")
public class MovieEntity {
@Id @GeneratedValue(generatorRef = "myIdGenerator")
private String id;
private String name;
}
使用业务密钥
我们一直在完整示例的 和 PersonEntity
中使用业务键。
人员的姓名是在构造时分配的,无论是由您的应用程序分配的,还是在通过 Spring Data 加载时分配的。MovieEntity
这只有在您找到一个稳定、唯一的业务密钥时才有可能,但可以创建出色的不可变域对象。
-
优点:使用业务键或自然键作为主键是自然的。 有问题的实体被清楚地识别出来,并且在大多数时候,在你的域的进一步建模中感觉恰到好处。
-
缺点:一旦你意识到你找到的 key 并不像你想象的那么稳定,作为主键的业务 key 将很难更新。 事实证明,即使承诺并非如此,它也可以改变。 除此之外,找到对事物真正唯一的标识符是很困难的。
请记住,在 Spring Data Neo4j 处理业务密钥之前,始终在域实体上设置业务密钥。
这意味着它无法确定实体是否为新实体(它始终假定实体为新实体),
除非还提供了 @Version
字段。