java - 使用 SessionFactory 时事务管理在 neo4j-omg 中不起作用
问题描述
我编写了一个小型 Spring Boot 应用程序,用于spring-boot-starter-data-neo4j
连接到 Neo4j 实例。
我想通过 Cypher 查询执行一些更新,但是在Session
使用SessionFactory
. 事务管理通过Neo4jRepository
.
出于测试目的,我编写了两个简单的服务,注释为@Transactional
:
使用 OGM 注释类和一个Neo4jRepository
:
@Service
@Transactional
public class OgmServiceImpl implements OgmService {
private final PersonRepository personRepository;
public OgmServiceImpl(PersonRepository personRepository) {
this.personRepository = personRepository;
}
@Override
public void storeData() {
personRepository.save(new Person("Jack"));
if (true) {
throw new IllegalStateException();
}
personRepository.save(new Person("Jill"));
}
}
执行 storeData() 方法时,Jack 和 Jill 都不会保存到 Neo4j。按预期工作。
另一个服务通过在 Neo4j 上执行 Cypher 查询来做同样的事情Session
:
@Service
@Transactional
public class CypherServiceImpl implements CypherService {
private final SessionFactory sessionFactory;
public CypherServiceImpl(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Override
public void storeData() {
Session session = sessionFactory.openSession();
session.query("CREATE (p:Person { name: 'Jack' })", Map.of());
if (true) {
throw new IllegalStateException();
}
session.query("CREATE (p:Person { name: 'Jill'})", Map.of());
}
}
但是,事务管理失败,因为 Jack 存储在 Neo4j 中。
对我来说,这种行为是非常出乎意料的。我可以通过显式启动事务来使事务管理工作,但这不是我喜欢的方式:
public void storeData() {
Session session = sessionFactory.openSession();
try (Transaction tx = session.beginTransaction()) {
session.query("CREATE (p:Person { name: 'Jack' })", Map.of());
if (true) {
throw new IllegalStateException();
}
session.query("CREATE (p:Person { name: 'Jill'})", Map.of());
tx.commit();
}
}
我是否需要SessionFactory
自己配置才能使其正常工作?为什么 Spring Boot 不处理这个问题?
解决方案
刚看了文档。根据文档,当您以编程方式调用SessionFactory#openSession
创建一个全新的会话时,该会话不一定在注释指定的事务范围内。@Transactional
为了进一步确保这一点,您可以尝试使用以下代码检查断言错误:
@Override
public void storeData() {
Session session = sessionFactory.openSession();
assert session.getTransaction() != null;
session.query("CREATE (p:Person { name: 'Jack' })", Map.of());
session.query("CREATE (p:Person { name: 'Jill'})", Map.of());
}
这应该会导致断言错误。不像hibernate,它提供了一种获取当前会话的方法,但我找不到neo4J-ogm 方法来做到这一点。
下面编写的代码有效,因为即使您正在创建一个全新的 Session,事务也是由您管理的。在这里,您正在创建一个自我管理的事务,而不是 Spring 容器管理的事务,尽管这通常不是一个好主意。
public void storeData() {
Session session = sessionFactory.openSession();
try (Transaction tx = session.beginTransaction()) {
session.query("CREATE (p:Person { name: 'Jack' })", Map.of());
if (true) {
throw new IllegalStateException();
}
session.query("CREATE (p:Person { name: 'Jill'})", Map.of());
tx.commit();
}
}
推荐阅读
- reactjs - 如何使用反应路由器dom显示嵌套组件?
- netsuite - DocuSign 和 NetSuite webhook 事件通知认证
- jquery - jquery css on change properties接收滚动条
- java - 如何从java中具有多个实现的接口获取类名
- javascript - 更改过滤数组中的布尔值
- ruby-on-rails - Capybara 没有使用 js 启动自己的服务器:true
- node.js - 在 Jenkinsfile 中从 yarn 运行 jest 从一个分支获取“jest: not found”,从另一个分支获取成功
- java - 如何让 webapp 在 Travis CI 上运行?
- selenium-webdriver - 为什么 WebDriver 不编辑合流页面?
- corda - 如何确保 Corda 流中的所有事务/子流都已完成?