如何在一个数据源的单个 Spring Boot 应用程序中混合 `autoCommit=true` 和 `autoCommit=true` @Transactional 操作?

问题描述 投票:0回答:1

我希望 Spring @Transactional 能够添加对

autoCommit=true
的支持,类似于
readOnly=true
选项。在我的 Spring Boot 应用程序中,我想混合使用:

    除一个方法外,所有
  1. autoCommit=false
     方法的 
    @Transactional
    (默认)语义。
  2. autoCommit=true
    一种
    @Transactional
    方法的(新)语义。

我认为Spring仅在数据源级别支持

autoCommit=true
,而不是
@Transactional
注释?

  • 长期=>请添加
    @Transactional
    autoCommit=true
    的支持,类似于
    readOnly=true
    。我认为两者对于很多用例都有意义,但目前仅支持后者。
  • 短期 => 请让我知道如何在 Spring Boot 应用程序中混合
    autoCommit=false
    autoCommit=true
    语义?我尝试过,但无法让它工作。

最后提供了示例代码。我失败的解决方法尝试的详细信息也在最后。


用例:运行 REST 客户端,针对 Spring Boot REST API 进行 10 次/秒的成功用户身份验证。然后尝试将其扩展到 100/秒和 1000/秒。

问题:身份验证提供程序同步调用

ApplicationEventListener<AuthenticationSuccessEvent>
,后者调用
@Service
来更新 JPA 用户实体中的两个字段(即
locked
last_login_date
)以及 @Version 字段。

我在高并发可扩展性测试中发现了这些瓶颈:

  1. Spring 端
    autoCommit=false
    内务管理 => 由于数据库内务管理调用而导致的延迟(即
    SET AUTOCOMMIT=0
    BEGIN
    COMMIT
    SET AUTOCOMMIT=1
  2. Spring 端重试 => 更新
    @Version
    重试,由于
    @Retryable
    模式下的
    READ COMMITTED
    语义
  3. PostgreSQL 端 WAL => 使用
    findById
    save
    为所有列生成 UPDATE 语句

我通过在 JpaRepository 中使用

@Modifying @Query
解决了 3 问题;请参阅示例代码。

我想使用

autoCommit=true
语义来解决 1。我认为这也会间接缓解 2。


用户表列:

  • id用户名密码电子邮件地址家庭地址 => 侦听器未更新
  • locked
    ,
    last_login_date
    ,
    version
    => 由听众更新

我对

@Transactional
的理解是,它大致将我的
@Service
方法翻译为对数据库的五个SQL客户端调用:

  1. 设置自动提交=0
  2. 开始
  3. 更新用户设置锁定= false,last_login_date = NOW(),版本=版本+ 1,其中id =?和版本=?
  4. 结束
  5. 设置自动提交=1

四个内务呼叫 1-2 和 4-5 是浪费。

  • 如果步骤 3 是选择,
    readOnly=true
    将消除步骤 1-2 和 4-5。
  • 由于步骤 3 是更新,
    autoCommit=true
    可以消除步骤 1-2 和 4-5。

示例代码

@Component
public class AuthenticationSuccessEventListener implements ApplicationListener<AuthenticationSuccessEvent> {
    @Override
    public void onApplicationEvent(AuthenticationSuccessEvent event) {
        Authentication authentication = event.getAuthentication();
        if (authentication instanceof MyAuthenticationSuccessEvent customEvent) {
            userService().updateSuccessfulAuthentication(customEvent.getUserId();
        }
    }
}
@Service
public class UserService {
    @Transactional
    @Retryable(value = {OptimisticLockingFailureException.class}, backoff = @Backoff(delay = 50))
    public void updateSuccessfulAuthentication(long userId) {
        userRepository.updateSuccessfulAuthentication(userId);
    }
}
public interface UserRepository extends JpaRepository<User, Long> {
    @Modifying
    @Query("UPDATE User u SET u.locked = false, u.lastLoginDate = NOW() WHERE u.id = :userId")
    void updateSuccessfulAuthentication(Long userId);
}

我尝试了这个解决方法,但没有成功

  1. 创建
    AutoCommitTransactionManager
    DataSourceTransactionManager的副本,并注释掉
    autoCommit=false
    内务代码。
  2. 创建
    AutoCommitTransactionManagerConfig
    DataSourceTransactionManagerAutoConfiguration 的副本,声明
    DataSourceTransactionManager
    bean(已删除条件),并添加新的
    AutoCommitTransactionManager
    bean。两个 TransactionManager 都引用相同的 DataSource bean(即我的 PostgreSQL 数据库实例)。
  3. 更改
    @Service
    方法以使用
    @Transactional("autoCommitTransactionManager")

我无法让上述工作发挥作用。豆子似乎互相踩踏,或者互相干扰。

我不知道这是否是一个有效的方法。如果我错过了什么,请告诉我,我会尝试。谢谢你。


总结:

从长远来看,我希望 Spring 能够提供

autoCommit=true
@Transactional
的选项。还有其他方法,但添加
autoCommit=true
是理想的选择。这是其他框架中的有效方法,不需要任何样板代码,也不需要任何重构来以其他方式解决瓶颈。

短期内,我希望能够让两个 TransactionManager bean 方法发挥作用。


java spring spring-boot spring-data-jpa spring-transactions
1个回答
0
投票

autoCommit
@Transactional
一起使用没有意义,并且违背了
@Transactional
的目的。如果您想要,请不要使用
@Transactional
,您将获得您认为需要的东西(但事实并非如此)。

使用

autoCommit
时,您基本上会放松对事务的控制,并将其留给数据库连接和/或数据库端的隐式事务。

设置

SET AUTOCOMMIT=0
的事实意味着您也将
DataSource
设置为
autoCommit
true
。将其设置为
false
以禁用
autoCommit
,您将摆脱
SET AUTOCOMMIT=0
/
SET AUTOCOMMIT=1
调用。如果您使用的是最新版本的 Spring Boot,这也会自动设置
hibernate.connection.provider_disables_autocommit
来改进 Hibernate。如果没有,您需要将
spring.jpa.properties.hibernate.connection.provider_disables_autocommit=true
添加到您的
application.properties
。 (有关更多信息,请参阅此博客)。

这样你就可以摆脱自动提交模式对事务的完全设置的影响。

对于交易的开始/结束,您可以或不应该做太多事情。数据库端总会有事务,所以你最好能控制事情。

© www.soinside.com 2019 - 2024. All rights reserved.