@@ -15,9 +15,15 @@ import java.time.Duration
1515 */
1616class TransactionRetryHandler (
1717 private val qualifierName : String = " database" ,
18- private val exceptionClassifier : ExceptionClassifier = DefaultExceptionClassifier ()
18+ private val exceptionClassifier : ExceptionClassifier = DefaultExceptionClassifier (),
19+ databaseType : DataSourceType ? = null
1920) {
2021
22+ constructor (
23+ qualifierName: String = " database" ,
24+ databaseType: DataSourceType ? = null
25+ ) : this (qualifierName, DefaultExceptionClassifier (databaseType), databaseType)
26+
2127 /* *
2228 * Executes a block with retry logic for transient database failures.
2329 */
@@ -85,7 +91,9 @@ interface ExceptionClassifier {
8591/* *
8692 * Default exception classifier that handles common database retry scenarios.
8793 */
88- open class DefaultExceptionClassifier : ExceptionClassifier {
94+ open class DefaultExceptionClassifier (
95+ private val databaseType : DataSourceType ? = null
96+ ) : ExceptionClassifier {
8997
9098 override fun isRetryable (th : Throwable ): Boolean {
9199 return when (th) {
@@ -98,9 +106,9 @@ open class DefaultExceptionClassifier : ExceptionClassifier {
98106
99107 protected fun isMessageRetryable (th : SQLException ): Boolean =
100108 isConnectionClosed(th) ||
101- isVitessTransactionNotFound(th ) ||
102- isCockroachRestartTransaction(th ) ||
103- isTidbWriteConflict(th )
109+ (databaseType == DataSourceType . VITESS_MYSQL && isRecoverableVitessException(th) ) ||
110+ (databaseType == DataSourceType . COCKROACHDB && isRecoverableCockroachException(th) ) ||
111+ (databaseType == DataSourceType . TIDB && isRecoverableTidbException(th) )
104112
105113 /* *
106114 * This is thrown as a raw SQLException from Hikari even though it is most certainly a recoverable exception.
@@ -109,6 +117,27 @@ open class DefaultExceptionClassifier : ExceptionClassifier {
109117 protected fun isConnectionClosed (th : SQLException ): Boolean =
110118 th.message.equals(" Connection is closed" )
111119
120+ /* *
121+ * Vitess-specific recoverable exceptions.
122+ */
123+ protected fun isRecoverableVitessException (th : SQLException ): Boolean {
124+ return isVitessTransactionNotFound(th)
125+ }
126+
127+ /* *
128+ * CockroachDB-specific recoverable exceptions.
129+ */
130+ protected fun isRecoverableCockroachException (th : SQLException ): Boolean {
131+ return isCockroachRestartTransaction(th)
132+ }
133+
134+ /* *
135+ * TiDB-specific recoverable exceptions.
136+ */
137+ protected fun isRecoverableTidbException (th : SQLException ): Boolean {
138+ return isTidbWriteConflict(th)
139+ }
140+
112141 /* *
113142 * We get this error as a MySQLQueryInterruptedException when a tablet gracefully terminates, we just need to retry
114143 * the transaction and the new primary should handle it.
@@ -118,7 +147,7 @@ open class DefaultExceptionClassifier : ExceptionClassifier {
118147 * not found (CallerID: )
119148 * ```
120149 */
121- protected fun isVitessTransactionNotFound (th : SQLException ): Boolean {
150+ private fun isVitessTransactionNotFound (th : SQLException ): Boolean {
122151 val message = th.message
123152 return message != null &&
124153 message.contains(" vttablet: rpc error" ) &&
@@ -132,7 +161,7 @@ open class DefaultExceptionClassifier : ExceptionClassifier {
132161 * it conflicted with another concurrent or recent transaction accessing the same data. The transaction needs to be
133162 * retried by the client." https://www.cockroachlabs.com/docs/stable/common-errors.html#restart-transaction
134163 */
135- protected fun isCockroachRestartTransaction (th : SQLException ): Boolean {
164+ private fun isCockroachRestartTransaction (th : SQLException ): Boolean {
136165 val message = th.message
137166 return th.errorCode == 40001 && message != null && message.contains(" restart transaction" )
138167 }
@@ -141,7 +170,7 @@ open class DefaultExceptionClassifier : ExceptionClassifier {
141170 * "Transactions in TiKV encounter write conflicts". This can happen when optimistic transaction mode is on. Conflicts
142171 * are detected during transaction commit https://docs.pingcap.com/tidb/dev/tidb-faq#error-9007-hy000-write-conflict
143172 */
144- protected fun isTidbWriteConflict (th : SQLException ): Boolean {
173+ private fun isTidbWriteConflict (th : SQLException ): Boolean {
145174 return th.errorCode == 9007
146175 }
147176
0 commit comments