【问题标题】:Spring Hibernate transaction - read only vs read writeSpring Hibernate 事务 - 只读与读写
【发布时间】:2021-06-07 03:52:46
【问题描述】:

我在使用 Spring Boot(2.3.7) + PostgreSQL v12(行级安全性)+ Hibernate (5.x) 时遇到了一个奇怪的问题。

这是我正在执行的步骤

  1. 过程接受输入变量并创建临时表。然后将该变量插入到临时表中。
  2. Spring Advice 对所有 @Service 注释执行并调用带有变量的过程(称为 custom_id)。
  3. @Transactional 属性在所有 @Service 类上指定。
  4. 已对正在查询和更新的表启用 PostgreSQL 行级安全性。
  5. 行级安全性根据临时表中存储的变量(custom_id 值)应用过滤器。
  6. 所有更新、选择、插入操作均使用JpaRepository 的自定义实现(基于接口)执行

只要在数据库上只执行选择操作,它就可以正常工作。但是开始失败,代码结合了选择和更新。由于无法找到临时表,该代码只是失败并显示一条消息。

我为 Spring 事务启用了跟踪,发现像这样的语句很少

无需为 XXX 创建交易

虽然执行更新操作的代码有类似的语句

获取 XXX 的交易

搜索了一段时间后,我意识到SimpleJpaRepository@Transactionreadonly 标志设置为true。这会导致 SELECT 操作在少事务模式下执行。

程序

create or replace procedure proc_context(dummy_id uuid) AS $context_var$
declare

begin

create temp table if not exists context_metadata
(
dummy_id uuid
)
on commit drop;

insert into context_metadata values(dummy_id);

end;
$context_var$ LANGUAGE plpgsql;

错误

以下错误记录在控制台中

ERROR: relation "context_metadata" does not exist

我尝试了什么

  1. 尝试实现自定义事务管理器并显式调用过程来设置临时变量值(不起作用)。参考下文
    protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {

    super.prepareSynchronization(status, definition);

    if (status.isNewTransaction() || status.isReadOnly() || status.isNewSynchronization()) {

    UUID someID = ....;

    Query query = entityManager.createNativeQuery("CALL proc_context(?);");

    query.setParameter(1, someID);

    query.executeUpdate();

    }

    }
  1. 尝试在所有存储库上将readonly 设置为false@Transactional 表示法。

我在寻找什么?

不幸的是,由于这种行为,行级安全实现在我的代码中不起作用。有什么方法可以使用全局属性禁用只读事务,或者为我提供解决此问题的任何提示?

【问题讨论】:

  • 它不会在没有事务的情况下运行,它将在只读事务中运行。 readonly 部分只是提示 hibernate 忽略脏检查。此外,如果已经有交易(当您声明自己使用 @Transactional 注释您的服务时应该是这种情况,那么它应该无关紧要,因为已经有正在进行的交易)。
  • 这就是我迷路的地方。我可以从日志中找出只有一个事务,并且正在执行创建/填充临时表的代码。更新查询根本失败,抱怨临时表不存在。

标签: java spring postgresql spring-boot transactions


【解决方案1】:

最后,经过两天的战斗,我可以弄清楚了。这个问题是多方面的。

  1. 我注意到 application.properties 文件中的 hibernate.transaction.flush_before_completion 属性设置为 true。我不得不删除该属性。
  2. 开发人员编写了一个非常混乱的代码来更新实体属性(执行选择,然后创建新实例,填充属性,然后调用保存方法)。所有这些都在更新一个属性。

测试了代码,一切正常。

【讨论】:

    猜你喜欢
    • 2012-03-01
    • 1970-01-01
    • 2014-11-12
    • 1970-01-01
    • 1970-01-01
    • 2019-09-04
    • 2015-03-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多