我希望 Spring @Transactional 能够添加对
autoCommit=true
的支持,类似于 readOnly=true
选项。在我的 Spring Boot 应用程序中,我想混合使用:
autoCommit=false
方法的
@Transactional
(默认)语义。autoCommit=true
一种 @Transactional
方法的(新)语义。我认为Spring仅在数据源级别支持
autoCommit=true
,而不是@Transactional
注释?
@Transactional
对autoCommit=true
的支持,类似于readOnly=true
。我认为两者对于很多用例都有意义,但目前仅支持后者。autoCommit=false
和 autoCommit=true
语义?我尝试过,但无法让它工作。最后提供了示例代码。我失败的解决方法尝试的详细信息也在最后。
用例:运行 REST 客户端,针对 Spring Boot REST API 进行 10 次/秒的成功用户身份验证。然后尝试将其扩展到 100/秒和 1000/秒。
问题:身份验证提供程序同步调用
ApplicationEventListener<AuthenticationSuccessEvent>
,后者调用 @Service
来更新 JPA 用户实体中的两个字段(即 locked
、last_login_date
)以及 @Version 字段。
我在高并发可扩展性测试中发现了这些瓶颈:
autoCommit=false
内务管理 => 由于数据库内务管理调用而导致的延迟(即 SET AUTOCOMMIT=0
、BEGIN
、COMMIT
、SET AUTOCOMMIT=1
)@Version
重试,由于 @Retryable
模式下的 READ COMMITTED
语义findById
和 save
为所有列生成 UPDATE 语句我通过在 JpaRepository 中使用
@Modifying @Query
解决了 3 问题;请参阅示例代码。
我想使用
autoCommit=true
语义来解决 1。我认为这也会间接缓解 2。
用户表列:
locked
, last_login_date
, version
=> 由听众更新我对
@Transactional
的理解是,它大致将我的@Service
方法翻译为对数据库的五个SQL客户端调用:
四个内务呼叫 1-2 和 4-5 是浪费。
readOnly=true
将消除步骤 1-2 和 4-5。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);
}
我尝试了这个解决方法,但没有成功
AutoCommitTransactionManager
,DataSourceTransactionManager的副本,并注释掉autoCommit=false
内务代码。AutoCommitTransactionManagerConfig
,DataSourceTransactionManagerAutoConfiguration 的副本,声明 DataSourceTransactionManager
bean(已删除条件),并添加新的 AutoCommitTransactionManager
bean。两个 TransactionManager 都引用相同的 DataSource bean(即我的 PostgreSQL 数据库实例)。@Service
方法以使用 @Transactional("autoCommitTransactionManager")
。我无法让上述工作发挥作用。豆子似乎互相踩踏,或者互相干扰。
我不知道这是否是一个有效的方法。如果我错过了什么,请告诉我,我会尝试。谢谢你。
总结:
从长远来看,我希望 Spring 能够提供
autoCommit=true
到 @Transactional
的选项。还有其他方法,但添加 autoCommit=true
是理想的选择。这是其他框架中的有效方法,不需要任何样板代码,也不需要任何重构来以其他方式解决瓶颈。
短期内,我希望能够让两个 TransactionManager bean 方法发挥作用。
将
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
。 (有关更多信息,请参阅此博客)。
这样你就可以摆脱自动提交模式对事务的完全设置的影响。
对于交易的开始/结束,您可以或不应该做太多事情。数据库端总会有事务,所以你最好能控制事情。