Neo4j 3.0.6和Neo4j ogm 2.0.5-在数据库上创建重复数据

Neo4j 3.0.6和Neo4j ogm 2.0.5-在数据库上创建重复数据,neo4j,graph-databases,spring-data-neo4j-4,neo4j-ogm,Neo4j,Graph Databases,Spring Data Neo4j 4,Neo4j Ogm,我对neo4j数据库有问题。当我尝试初始化数据时,应该只创建一个样本数据,但有时当我尝试初始化数据时,它会创建两个样本数据。没有第二次打电话的痕迹。这是我的Neo4j的配置 @Configuration @EnableNeo4jRepositories(basePackages = "com.example.neo.repository") @EnableTransactionManagement public class Neo4jConfig extends Neo4jConfigurati

我对neo4j数据库有问题。当我尝试初始化数据时,应该只创建一个样本数据,但有时当我尝试初始化数据时,它会创建两个样本数据。没有第二次打电话的痕迹。这是我的Neo4j的配置

@Configuration
@EnableNeo4jRepositories(basePackages = "com.example.neo.repository")
@EnableTransactionManagement
public class Neo4jConfig extends Neo4jConfiguration {
    @Override
    @Bean
    public SessionFactory getSessionFactory() {
        // with domain entity base package(s)
        return new SessionFactory("com.example.neo.model", "BOOT-INF.classes.com.example.neo.model");
    }

    // needed for session in view in web-applications
    @Override
    @Bean
    @Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
    public Session getSession() throws Exception {
        return super.getSession();
    }
}
这就是我调用函数的方式

@RequestMapping(value = "/initCurrency")
public ModelAndView initCurrency() {
    initializationService.initCurrency();

    ModelAndView model = new ModelAndView("redirect:/");
    return model;
}
这是initializationService函数

private String[][] currencyList = {
        { "USD", "7.5" },
        { "DKK", "1" },
        { "AFN", "1"},{ "EUR", "1"},{ "ALL", "1"},{ "DZD", "1"},{ "USD", "1"},{ "AOA", "1"},{ "XCD", "1"},
        { "ARS", "1"},{ "AMD", "1"},{ "AWG", "1"},{ "SHP", "1"},{ "AUD", "1"},{ "AZN", "1"},{ "BSD", "1"},
        { "BHD", "1"},{ "BDT", "1"},{ "BBD", "1"}
}
@Override
public void initCurrency() {
    for (String[] currency : currencyList) {
        Currency existCurrency = currencyService.findByName(currency[0]);

        if (existCurrency == null) {
            existCurrency = new Currency(currency[0], Double.valueOf(currency[1]));
            currencyService.save(existCurrency);
        }
    }
}

避免重复的唯一可靠方法是对物业进行实际检查:

CREATE CONSTRAINT ON (n:Currency) ASSERT n.name IS UNIQUE;
SDN 4.[0-2](目前)中没有办法从模型中创建这样的约束(SDN 3.x中有
@index
@index(unique=true)
注释),因此您必须独立运行查询(例如使用!)

在并发环境中,仅执行查找来保护创建是不够的(顺序调用是可以的),因为读和写之间没有锁定,这可能导致以下交叉执行的情况:

  • 线程A检查是否存在,但未找到节点
  • 线程B检查是否存在,也没有找到节点
  • 线程A创建一个名为“USB”的货币节点
  • 线程B创建另一个同名的货币节点

由于最终的结果是重复的,因此发生了两个并发调用。超时时间很短并配置为重试的负载平衡器?激活HTTP日志,在Spring控制器或服务中添加一些日志记录,使用
tcpdump
捕获流量,等等。一旦unicity约束激活,将更容易隔离第二个调用,因为您将得到一个异常。

也许您应该在货币代码上添加唯一性约束-两者都可以防止重复,并揭示出问题所在。@Jasperbluse我已经添加了唯一Id,并使用findByName防止重复。如果存在货币,则应跳过保存代码。但是当我检查neo4j数据库时,有两个数据具有不同的唯一Id。Jasper的意思是你应该使货币的名称唯一,使用
对(n:currency)断言创建约束n.name是唯一的(假设
USD
进入
currency
标签的
name
属性)。应用程序将无法创建具有相同货币名称的2个节点,第二个节点将失败,并且您将在日志中发现异常。具有唯一标识符(名称、uuid等)的实体应具有约束(这将创建索引并加快查找速度!)。并非所有实体都是这样:如果实体
B
仅存在于实体
A
的上下文中,则它可能没有全局唯一的属性。例如,如果您有与
软件
节点相关的
版本
节点,则这些版本不是全局唯一的,
Neo4j
Windows
都可以有
3.0版
。您的代码仅在顺序调用init服务时防止重复。如果您有并发调用,那么当线程执行交错时,这是一个竞争条件:线程a检查它不存在,线程B检查它不存在,线程a创建货币,线程B也创建货币。是的。这是因为两个线程同时运行,这就是它创建重复数据的原因。就像你的解释。无论如何,感谢您提供的这些信息,非常有用。值得一提的是,OGM中支持
@Index
@Index(unique=true)