【问题标题】:Spring+Hibernate+SQLite transaction odditiesSpring+Hibernate+SQLite 事务异常
【发布时间】:2016-08-27 15:18:57
【问题描述】:

我在 Spring + Hibernate + SQLite 堆栈中回滚失败的事务时遇到问题。

这是我的示例的主要类

看方法TestBean.testMethod()

public void testMethod()    {
    entityManager.persist(createOrder("1"));
    entityManager.persist(createOrder("2"));
    entityManager.persist(createOrder("3"));
    entityManager.createQuery("from Order").getResultList();
    entityManager.persist(createOrder("4"));
    throw new RuntimeException("Managed");
}

它创建并保留一些订单实体。 在一些创作之间,它从数据库中读取一些数据。 最后抛出 RuntimeException 模拟方法调用失败,强制 Spring 回滚事务。

执行后,我打开数据库并查看,它完全回滚了仅最后创建的实体(createOrder("4"))和所有其他(名称为“1”、“2”和“3”)仍然存在于数据库。但是由于 TestBean 被标记为 @Transactional,所以它应该删除在一个事务方法 testMethod() 中创建的所有四个实体。

我尝试了 SQLIte 中的所有 journal_mode,但回滚仍然无效。

有什么想法吗?

【问题讨论】:

  • Hibernate 似乎在每个 em.persist() 调用上调用 JdbcIsolationDelegate#delegateWork。同时,方法 JdbcIsolationDelegate#delegateWork 调用 Connection#commit 破坏了 JPA/Hibernate 框架中的所有事务交互

标签: spring hibernate sqlite jpa transactions


【解决方案1】:

很久以后,我找到了问题的真正原因——它是应用程序中所有实体的@GeneratedValue注解的策略类型。

注解默认提供的策略是AUTO,这意味着Hibernate会使用目标数据库中自己的表(hibernate_sequence)来生成ID值。 Hibernate 在单独的事务中调用查询(从 hibernate_sequence 中选择当前值)——在这一点上我们遇到了问题。

如果您使用通用多连接数据源,Hibernate 会尝试获取新连接,但 SQLite 只能有一个活动连接 - 我们会收到“数据库文件已锁定”错误。 如果您使用 Spring 的 SingleConnectionDataSource 防止连接关闭,那么 Hibernate 将重用现有连接,但会创建新的单独事务。新交易会成功完成,但旧交易要求新ID会失败。

所以解决方案非常简单,只需确保所有您的实体都像这样注释

@GeneratedValue(strategy = GenerationType.IDENTITY)

因此,在这种情况下,Hibernate 会将 ID 值的生成委托给底层数据库。

【讨论】:

  • 似乎我也被这件事烧伤了,还试图让 Spring Boot 与 sqlite3 一起工作:因为这个原因,我在 @Transactional 注释中不断收到“数据库已锁定”异常 - 我使用的是 GenerationType.SEQUENCE 和Hibernate 试图在创建新实体的同时管理序列生成。我一切换到 GenerationType.IDENTITY,它就起作用了。
猜你喜欢
  • 1970-01-01
  • 2023-03-18
  • 2018-02-04
  • 1970-01-01
  • 2015-12-30
  • 2016-11-03
  • 2015-02-03
  • 2011-11-04
  • 1970-01-01
相关资源
最近更新 更多