如何使用Spring正确重试可序列化的事务?

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

我正在针对PostgreSQL v12数据库进行开发。我正在使用SERIALIZABLE交易。一般想法是,当PostgreSQL检测到序列化异常时,应重试整个事务。

我正在使用Spring的SERIALIZABLE将数据库异常转换为Spring的异常类。该异常转换器应将PostgreSQL错误AbstractFallbackSQLExceptionTranslator转换为AbstractFallbackSQLExceptionTranslator。 Spring JDBC维护一个40001/serialization_failure来将PostgreSQL特定的代码40001映射到数据库异常的通用serialization_failure类,该类将API用户转换为ConcurrencyFailureException

我的想法是依靠Spring Retry项目重试ConcurrencyFailureException事务,该事务由于以下序列化错误而暂停:

mapping file

在服务实现中,我只需将40001替换为cannotSerializeTransactionCodes并完成此操作。

现在,回到PostgreSQL。本质上,可以在两个阶段检测序列化异常:

  1. 执行语句期间
  2. 在事务的提交阶段期间

[似乎Spring的ConcurrencyFailureException正确地翻译了在执行一条语句时检测到的序列化异常,但在提交阶段未能转换该序列化异常。考虑以下堆栈跟踪:

SERIALIZABLE

您可以看到,PostgreSQL检测到序列化异常(@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Retryable(include = ConcurrencyFailureException.class, maxAttempts = ..., backoff = ...) @Transactional(isolation = Isolation.SERIALIZABLE) public @interface SerializableTransactionRetry { } ),但是Spring将其转换为@Transactional而不是@SerializableTransactionRetry

[我可以更改上面的AbstractFallbackSQLExceptionTranslator注释,使其也包含org.springframework.transaction.TransactionSystemException: Could not commit JDBC transaction; nested exception is org.postgresql.util.PSQLException: ERROR: could not serialize access due to read/write dependencies among transactions Detail: Reason code: Canceled on identification as a pivot, during commit attempt. Hint: The transaction might succeed if retried. at org.springframework.jdbc.datasource.DataSourceTransactionManager.doCommit(DataSourceTransactionManager.java:332) at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:746) at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:714) at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:533) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:304) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.retry.interceptor.RetryOperationsInterceptor$1.doWithRetry(RetryOperationsInterceptor.java:91) at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:287) at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:164) at org.springframework.retry.interceptor.RetryOperationsInterceptor.invoke(RetryOperationsInterceptor.java:118) at org.springframework.retry.annotation.AnnotationAwareRetryOperationsInterceptor.invoke(AnnotationAwareRetryOperationsInterceptor.java:153) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ,但是我认为那是错误的,因为现在我们将重试任何类型的事务错误,这不是我们想要的。] >

这是Spring的ERROR: could not serialize access due to ...的缺点吗?我正在使用Spring 5.2.1。

我正在针对PostgreSQL v12数据库进行开发。我正在使用SERIALIZABLE交易。一般想法是,当PostgreSQL检测到序列化异常时,应重试完整的...

spring postgresql transactions spring-jdbc spring-retry
1个回答
0
投票

TransactionSystemException中所述,TransactionSystemException实际上未用于提交阶段发生的SQL异常。

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