Neo4j: явная пессимистическая блокировка через Java API или Cypher

Есть ли способ вручную получить блокировку записи на определенном наборе узлов через Neo4J Java API или Cypher?

В документации есть примеры, но только для встроенной версии Neo4j. Стандартный интерфейс Java Transaction не содержит таких методов: https://neo4j.com/docs/api/java-driver/current/org/neo4j/driver/v1/Transaction.html

Также я не могу найти способ сделать это через Cypher.


person silent-box    schedule 25.04.2018    source источник
comment
Вы решили свой вопрос? Может быть, вы можете поделиться кодом, пожалуйста?   -  person Steffen Harbich    schedule 15.10.2019


Ответы (2)


Вы можете взять блокировку записи, записав в узел, например, установив или удалив свойство. Я думаю, что это также работает при удалении несуществующих свойств.

Если у вас установлены процедуры APOC, вы можете вызвать процедуру apoc.lock.nodes(), передав это список узлов для блокировки.

person InverseFalcon    schedule 25.04.2018
comment
Это работает для меня, спасибо. Сложность заключается в том, что вам нужно сделать что-то вроде transaction.run(...).consume(), чтобы заблокировать поток из-за API ленивых транзакций. - person silent-box; 26.04.2018
comment
@silent-box Итак, вы изменили узел, чтобы получить блокировку? - person Steffen Harbich; 15.10.2019

Чтобы расширить ответ @InverseFalcon, вот пример блокировки записи путем записи в узел:

@Test
public void testPessimisticLocking() throws InterruptedException {
    txn.execute(status -> {
        session.query("CREATE (n:Lock {uuid:'test'})", Map.of(), false);
        return null;
    });

    ExecutorService executor = Executors.newFixedThreadPool(2);
    Runnable task = () -> {
        LOG.debug("Starting task");

        txn.execute(status -> {
            long time = System.nanoTime();
            LOG.debug("Locking node with time={}", time);
            session.query("MATCH (n:Lock {uuid:'test'}) SET n.time = {0}", Map.of("0", time), false);

            LOG.debug("Query done, waiting some time...");
            try {
                Thread.sleep(5000);
            }
            catch (InterruptedException e) {
                LOG.warn("Interrupted", e);
            }
            LOG.debug("Waiting done");

            return null;
        });

        LOG.debug("Finished task");
    };

    for (int i = 0; i < 2; i++) {
        executor.execute(task);
    }

    executor.shutdown();
    executor.awaitTermination(20, TimeUnit.MINUTES);
}

Тест создает узел с меткой «Блокировка». Он запускает две задачи параллельно, которые пытаются получить блокировку записи на узле. Каждая задача ожидает 5 секунд внутри транзакции после получения блокировки (симулирует рабочую нагрузку). Вывод отладки:

2019-10-26 09:47:09,502 [pool-3-thread-1] DEBUG - Starting task
2019-10-26 09:47:09,508 [pool-3-thread-1] DEBUG - Locking node with time=82297334790500
2019-10-26 09:47:09,513 [pool-3-thread-2] DEBUG - Starting task
2019-10-26 09:47:09,515 [pool-3-thread-2] DEBUG - Locking node with time=82297342219000
2019-10-26 09:47:09,605 [pool-3-thread-2] DEBUG - Query done, waiting some time...
2019-10-26 09:47:14,627 [pool-3-thread-2] DEBUG - Waiting done
2019-10-26 09:47:14,643 [pool-3-thread-1] DEBUG - Query done, waiting some time...
2019-10-26 09:47:14,645 [pool-3-thread-2] DEBUG - Finished task
2019-10-26 09:47:19,643 [pool-3-thread-1] DEBUG - Waiting done
2019-10-26 09:47:19,841 [pool-3-thread-1] DEBUG - Finished task

В журнале вы можете видеть, что одна задача получает блокировку только тогда, когда другая задача завершила транзакцию.

person Steffen Harbich    schedule 26.10.2019