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