Neo4j密码合并查询隔离级别

Neo4j密码合并查询隔离级别,neo4j,spring-data-neo4j,Neo4j,Spring Data Neo4j,前几天我遇到了这个要点,认为它对于跨HA集群生成OrderID很方便。我创建了一个简单的实现,单元测试失败了,因为count字段没有以线程安全的方式提供唯一的值 报纸上有安德烈斯泰勒的评论,内容如下 我们将在2.0中更多地研究隔离。这个问题应该在最终发布之前解决 我使用的是Neo4J embedded 2.1.3、Neo HA和Spring数据Neo4J 3.1.4,虽然我在发行说明中找不到任何明确的内容,但已删除了临时功能警告 我相信匹配查询的创建部分是孤立的,但我相信匹配部分在处理陈旧数据,

前几天我遇到了这个要点,认为它对于跨HA集群生成OrderID很方便。我创建了一个简单的实现,单元测试失败了,因为count字段没有以线程安全的方式提供唯一的值

报纸上有安德烈斯泰勒的评论,内容如下

我们将在2.0中更多地研究隔离。这个问题应该在最终发布之前解决

我使用的是Neo4J embedded 2.1.3、Neo HA和Spring数据Neo4J 3.1.4,虽然我在发行说明中找不到任何明确的内容,但已删除了
临时功能
警告

我相信匹配查询的创建部分是孤立的,但我相信匹配部分在处理陈旧数据,获取到单个唯一节点的写入锁,但在等待采集后不会重新读取数据。查看默认隔离似乎是读提交的,因为我的合并查询的性质(组合读/写语义-
nid.count=nid.count+1
)我应该在执行操作之前手动获取独占锁吗

代码片段:

节点:

@NodeEntity
public class UniqueId {

  @GraphId
  private Long id;

  @Indexed(indexType=IndexType.LABEL, unique=true)
  private String type;

  private long count;

  //getters/setters/stuff
}
public interface UniqueIdRepository extends GraphRepository<UniqueId> {

  @Query(value = "MERGE (nid:UniqueId{type:{0}}) " +
                 "ON CREATE SET nid:_UniqueId, nid.count = 1 " +
                 "ON MATCH SET nid.count = nid.count + 1 " +
                 "RETURN nid.count")
  public long generateUid(String type);
}
@Override
@Transactional
public Long generateOrderId() {
    return idRepository.generateUid("Order");
}
@Test
public void testLots() throws Exception {       
    final Map<Long, Object> ids = new ConcurrentHashMap<>();

    Thread t1 = new GenerateRunnable(200, ids);
    Thread t2 = new GenerateRunnable(200, ids);
    Thread t3 = new GenerateRunnable(200, ids);
    Thread t4 = new GenerateRunnable(200, ids);
    Thread t5 = new GenerateRunnable(200, ids);

    //Run method now just contains...
    // for (int i = 0; i < iterations; ++i) {
    //      Long uid = idService.generateOrderId();
    //      objects.put(uid, PRESENT);
    //      System.out.println(uid);
    //  }

    t1.start();
    t2.start();
    t3.start();
    t4.start();
    t5.start();

    t1.join();
    t2.join();
    t3.join();
    t4.join();
    t5.join();

    assertThat(ids.size(), equalTo(1000));
}
存储库:

@NodeEntity
public class UniqueId {

  @GraphId
  private Long id;

  @Indexed(indexType=IndexType.LABEL, unique=true)
  private String type;

  private long count;

  //getters/setters/stuff
}
public interface UniqueIdRepository extends GraphRepository<UniqueId> {

  @Query(value = "MERGE (nid:UniqueId{type:{0}}) " +
                 "ON CREATE SET nid:_UniqueId, nid.count = 1 " +
                 "ON MATCH SET nid.count = nid.count + 1 " +
                 "RETURN nid.count")
  public long generateUid(String type);
}
@Override
@Transactional
public Long generateOrderId() {
    return idRepository.generateUid("Order");
}
@Test
public void testLots() throws Exception {       
    final Map<Long, Object> ids = new ConcurrentHashMap<>();

    Thread t1 = new GenerateRunnable(200, ids);
    Thread t2 = new GenerateRunnable(200, ids);
    Thread t3 = new GenerateRunnable(200, ids);
    Thread t4 = new GenerateRunnable(200, ids);
    Thread t5 = new GenerateRunnable(200, ids);

    //Run method now just contains...
    // for (int i = 0; i < iterations; ++i) {
    //      Long uid = idService.generateOrderId();
    //      objects.put(uid, PRESENT);
    //      System.out.println(uid);
    //  }

    t1.start();
    t2.start();
    t3.start();
    t4.start();
    t5.start();

    t1.join();
    t2.join();
    t3.join();
    t4.join();
    t5.join();

    assertThat(ids.size(), equalTo(1000));
}
简单单元测试:

@NodeEntity
public class UniqueId {

  @GraphId
  private Long id;

  @Indexed(indexType=IndexType.LABEL, unique=true)
  private String type;

  private long count;

  //getters/setters/stuff
}
public interface UniqueIdRepository extends GraphRepository<UniqueId> {

  @Query(value = "MERGE (nid:UniqueId{type:{0}}) " +
                 "ON CREATE SET nid:_UniqueId, nid.count = 1 " +
                 "ON MATCH SET nid.count = nid.count + 1 " +
                 "RETURN nid.count")
  public long generateUid(String type);
}
@Override
@Transactional
public Long generateOrderId() {
    return idRepository.generateUid("Order");
}
@Test
public void testLots() throws Exception {       
    final Map<Long, Object> ids = new ConcurrentHashMap<>();

    Thread t1 = new GenerateRunnable(200, ids);
    Thread t2 = new GenerateRunnable(200, ids);
    Thread t3 = new GenerateRunnable(200, ids);
    Thread t4 = new GenerateRunnable(200, ids);
    Thread t5 = new GenerateRunnable(200, ids);

    //Run method now just contains...
    // for (int i = 0; i < iterations; ++i) {
    //      Long uid = idService.generateOrderId();
    //      objects.put(uid, PRESENT);
    //      System.out.println(uid);
    //  }

    t1.start();
    t2.start();
    t3.start();
    t4.start();
    t5.start();

    t1.join();
    t2.join();
    t3.join();
    t4.join();
    t5.join();

    assertThat(ids.size(), equalTo(1000));
}
@测试
public void testLots()引发异常{
最终映射ID=新的ConcurrentHashMap();
线程t1=新的GeneratorUnnable(200,ID);
线程t2=新的GeneratorUnnable(200,ID);
线程t3=新的GeneratorUnnable(200,ID);
线程t4=新的GeneratorUnnable(200,ID);
螺纹t5=新的发电机轴承(200,内径);
//Run方法现在只包含。。。
//对于(int i=0;i
虽然run方法正在使用服务,但我也直接调用了存储库,使用SDN neo4j模板运行查询,并直接使用ExecutionEngine—在后面的案例中手动创建和提交事务

我确实开始了一次对话,Michael善意地帮助我解决了查询语义中的一个错误,但我把对话带到这里来,因为我相信我的代码中有错误,或者我的理解有问题,而不是Neo4J本身的问题

如果我能正确地阅读Scala,我可能有更好的机会自己完成这项工作,因此我将把它放在我的学习列表中,但是我注意到,在调试时,我在TransactionBoundQueryContext$NodeOperations.setProperty中进入等待状态(此时,已经通过了MergeNodeAction的findNodes组件,正在获取和释放锁,现在正在处理
onMatch.foreach(…)
code MergeNodeAction:86)


我有其他机制来生成这个值,但这看起来是一个非常简洁的解决方案,我做错了什么吗?

所以我不知道这是否是一个bug,或者我是否以一种非预期的方式使用了MERGE,可能我的问题很长,很杂乱,让那些知道得更好的人失望了……无论如何,我已经手动锁定了我要对其保持控制的节点:

Transaction tx = template.getGraphDatabase().beginTx();

try {
    tx.acquireWriteLock(lockNode);
    long id = idRepository.generateUid(TYPE_ORDER);
    tx.success();
    return id;
}
finally {
    tx.close();
}
其中,
generateUid
是与原始问题中相同的查询。当然,我负责访问和更新值,而不是将其延迟到数据库引擎,但我以这种方式生成唯一的增量ID