1
1
/*
2
- * Copyright 2002-2018 the original author or authors.
2
+ * Copyright 2002-2020 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
35
35
import org .springframework .jdbc .BadSqlGrammarException ;
36
36
import org .springframework .jdbc .InvalidResultSetAccessException ;
37
37
import org .springframework .lang .Nullable ;
38
+ import org .springframework .util .function .SingletonSupplier ;
39
+ import org .springframework .util .function .SupplierUtils ;
38
40
39
41
/**
40
42
* Implementation of {@link SQLExceptionTranslator} that analyzes vendor-specific error codes.
@@ -76,7 +78,7 @@ public class SQLErrorCodeSQLExceptionTranslator extends AbstractFallbackSQLExcep
76
78
77
79
/** Error codes used by this translator. */
78
80
@ Nullable
79
- private SQLErrorCodes sqlErrorCodes ;
81
+ private SingletonSupplier < SQLErrorCodes > sqlErrorCodes ;
80
82
81
83
82
84
/**
@@ -88,7 +90,7 @@ public SQLErrorCodeSQLExceptionTranslator() {
88
90
}
89
91
90
92
/**
91
- * Create a SQL error code translator for the given DataSource.
93
+ * Create an SQL error code translator for the given DataSource.
92
94
* Invoking this constructor will cause a Connection to be obtained
93
95
* from the DataSource to get the meta-data.
94
96
* @param dataSource the DataSource to use to find meta-data and establish
@@ -101,7 +103,7 @@ public SQLErrorCodeSQLExceptionTranslator(DataSource dataSource) {
101
103
}
102
104
103
105
/**
104
- * Create a SQL error code translator for the given database product name.
106
+ * Create an SQL error code translator for the given database product name.
105
107
* Invoking this constructor will avoid obtaining a Connection from the
106
108
* DataSource to get the meta-data.
107
109
* @param dbName the database product name that identifies the error codes entry
@@ -114,13 +116,13 @@ public SQLErrorCodeSQLExceptionTranslator(String dbName) {
114
116
}
115
117
116
118
/**
117
- * Create a SQLErrorCode translator given these error codes.
119
+ * Create an SQLErrorCode translator given these error codes.
118
120
* Does not require a database meta-data lookup to be performed using a connection.
119
121
* @param sec error codes
120
122
*/
121
123
public SQLErrorCodeSQLExceptionTranslator (SQLErrorCodes sec ) {
122
124
this ();
123
- this .sqlErrorCodes = sec ;
125
+ this .sqlErrorCodes = SingletonSupplier . of ( sec ) ;
124
126
}
125
127
126
128
@@ -134,7 +136,9 @@ public SQLErrorCodeSQLExceptionTranslator(SQLErrorCodes sec) {
134
136
* @see java.sql.DatabaseMetaData#getDatabaseProductName()
135
137
*/
136
138
public void setDataSource (DataSource dataSource ) {
137
- this .sqlErrorCodes = SQLErrorCodesFactory .getInstance ().getErrorCodes (dataSource );
139
+ this .sqlErrorCodes =
140
+ SingletonSupplier .of (() -> SQLErrorCodesFactory .getInstance ().resolveErrorCodes (dataSource ));
141
+ this .sqlErrorCodes .get (); // try early initialization - otherwise the supplier will retry later
138
142
}
139
143
140
144
/**
@@ -146,15 +150,15 @@ public void setDataSource(DataSource dataSource) {
146
150
* @see java.sql.DatabaseMetaData#getDatabaseProductName()
147
151
*/
148
152
public void setDatabaseProductName (String dbName ) {
149
- this .sqlErrorCodes = SQLErrorCodesFactory .getInstance ().getErrorCodes (dbName );
153
+ this .sqlErrorCodes = SingletonSupplier . of ( SQLErrorCodesFactory .getInstance ().getErrorCodes (dbName ) );
150
154
}
151
155
152
156
/**
153
157
* Set custom error codes to be used for translation.
154
158
* @param sec custom error codes to use
155
159
*/
156
160
public void setSqlErrorCodes (@ Nullable SQLErrorCodes sec ) {
157
- this .sqlErrorCodes = sec ;
161
+ this .sqlErrorCodes = SingletonSupplier . ofNullable ( sec ) ;
158
162
}
159
163
160
164
/**
@@ -164,7 +168,7 @@ public void setSqlErrorCodes(@Nullable SQLErrorCodes sec) {
164
168
*/
165
169
@ Nullable
166
170
public SQLErrorCodes getSqlErrorCodes () {
167
- return this .sqlErrorCodes ;
171
+ return SupplierUtils . resolve ( this .sqlErrorCodes ) ;
168
172
}
169
173
170
174
@@ -175,7 +179,6 @@ protected DataAccessException doTranslate(String task, @Nullable String sql, SQL
175
179
if (sqlEx instanceof BatchUpdateException && sqlEx .getNextException () != null ) {
176
180
SQLException nestedSqlEx = sqlEx .getNextException ();
177
181
if (nestedSqlEx .getErrorCode () > 0 || nestedSqlEx .getSQLState () != null ) {
178
- logger .debug ("Using nested SQLException from the BatchUpdateException" );
179
182
sqlEx = nestedSqlEx ;
180
183
}
181
184
}
@@ -187,8 +190,9 @@ protected DataAccessException doTranslate(String task, @Nullable String sql, SQL
187
190
}
188
191
189
192
// Next, try the custom SQLException translator, if available.
190
- if (this .sqlErrorCodes != null ) {
191
- SQLExceptionTranslator customTranslator = this .sqlErrorCodes .getCustomSqlExceptionTranslator ();
193
+ SQLErrorCodes sqlErrorCodes = getSqlErrorCodes ();
194
+ if (sqlErrorCodes != null ) {
195
+ SQLExceptionTranslator customTranslator = sqlErrorCodes .getCustomSqlExceptionTranslator ();
192
196
if (customTranslator != null ) {
193
197
DataAccessException customDex = customTranslator .translate (task , sql , sqlEx );
194
198
if (customDex != null ) {
@@ -198,9 +202,9 @@ protected DataAccessException doTranslate(String task, @Nullable String sql, SQL
198
202
}
199
203
200
204
// Check SQLErrorCodes with corresponding error code, if available.
201
- if (this . sqlErrorCodes != null ) {
205
+ if (sqlErrorCodes != null ) {
202
206
String errorCode ;
203
- if (this . sqlErrorCodes .isUseSqlStateForTranslation ()) {
207
+ if (sqlErrorCodes .isUseSqlStateForTranslation ()) {
204
208
errorCode = sqlEx .getSQLState ();
205
209
}
206
210
else {
@@ -215,7 +219,7 @@ protected DataAccessException doTranslate(String task, @Nullable String sql, SQL
215
219
216
220
if (errorCode != null ) {
217
221
// Look for defined custom translations first.
218
- CustomSQLErrorCodesTranslation [] customTranslations = this . sqlErrorCodes .getCustomTranslations ();
222
+ CustomSQLErrorCodesTranslation [] customTranslations = sqlErrorCodes .getCustomTranslations ();
219
223
if (customTranslations != null ) {
220
224
for (CustomSQLErrorCodesTranslation customTranslation : customTranslations ) {
221
225
if (Arrays .binarySearch (customTranslation .getErrorCodes (), errorCode ) >= 0 &&
@@ -230,43 +234,43 @@ protected DataAccessException doTranslate(String task, @Nullable String sql, SQL
230
234
}
231
235
}
232
236
// Next, look for grouped error codes.
233
- if (Arrays .binarySearch (this . sqlErrorCodes .getBadSqlGrammarCodes (), errorCode ) >= 0 ) {
237
+ if (Arrays .binarySearch (sqlErrorCodes .getBadSqlGrammarCodes (), errorCode ) >= 0 ) {
234
238
logTranslation (task , sql , sqlEx , false );
235
239
return new BadSqlGrammarException (task , (sql != null ? sql : "" ), sqlEx );
236
240
}
237
- else if (Arrays .binarySearch (this . sqlErrorCodes .getInvalidResultSetAccessCodes (), errorCode ) >= 0 ) {
241
+ else if (Arrays .binarySearch (sqlErrorCodes .getInvalidResultSetAccessCodes (), errorCode ) >= 0 ) {
238
242
logTranslation (task , sql , sqlEx , false );
239
243
return new InvalidResultSetAccessException (task , (sql != null ? sql : "" ), sqlEx );
240
244
}
241
- else if (Arrays .binarySearch (this . sqlErrorCodes .getDuplicateKeyCodes (), errorCode ) >= 0 ) {
245
+ else if (Arrays .binarySearch (sqlErrorCodes .getDuplicateKeyCodes (), errorCode ) >= 0 ) {
242
246
logTranslation (task , sql , sqlEx , false );
243
247
return new DuplicateKeyException (buildMessage (task , sql , sqlEx ), sqlEx );
244
248
}
245
- else if (Arrays .binarySearch (this . sqlErrorCodes .getDataIntegrityViolationCodes (), errorCode ) >= 0 ) {
249
+ else if (Arrays .binarySearch (sqlErrorCodes .getDataIntegrityViolationCodes (), errorCode ) >= 0 ) {
246
250
logTranslation (task , sql , sqlEx , false );
247
251
return new DataIntegrityViolationException (buildMessage (task , sql , sqlEx ), sqlEx );
248
252
}
249
- else if (Arrays .binarySearch (this . sqlErrorCodes .getPermissionDeniedCodes (), errorCode ) >= 0 ) {
253
+ else if (Arrays .binarySearch (sqlErrorCodes .getPermissionDeniedCodes (), errorCode ) >= 0 ) {
250
254
logTranslation (task , sql , sqlEx , false );
251
255
return new PermissionDeniedDataAccessException (buildMessage (task , sql , sqlEx ), sqlEx );
252
256
}
253
- else if (Arrays .binarySearch (this . sqlErrorCodes .getDataAccessResourceFailureCodes (), errorCode ) >= 0 ) {
257
+ else if (Arrays .binarySearch (sqlErrorCodes .getDataAccessResourceFailureCodes (), errorCode ) >= 0 ) {
254
258
logTranslation (task , sql , sqlEx , false );
255
259
return new DataAccessResourceFailureException (buildMessage (task , sql , sqlEx ), sqlEx );
256
260
}
257
- else if (Arrays .binarySearch (this . sqlErrorCodes .getTransientDataAccessResourceCodes (), errorCode ) >= 0 ) {
261
+ else if (Arrays .binarySearch (sqlErrorCodes .getTransientDataAccessResourceCodes (), errorCode ) >= 0 ) {
258
262
logTranslation (task , sql , sqlEx , false );
259
263
return new TransientDataAccessResourceException (buildMessage (task , sql , sqlEx ), sqlEx );
260
264
}
261
- else if (Arrays .binarySearch (this . sqlErrorCodes .getCannotAcquireLockCodes (), errorCode ) >= 0 ) {
265
+ else if (Arrays .binarySearch (sqlErrorCodes .getCannotAcquireLockCodes (), errorCode ) >= 0 ) {
262
266
logTranslation (task , sql , sqlEx , false );
263
267
return new CannotAcquireLockException (buildMessage (task , sql , sqlEx ), sqlEx );
264
268
}
265
- else if (Arrays .binarySearch (this . sqlErrorCodes .getDeadlockLoserCodes (), errorCode ) >= 0 ) {
269
+ else if (Arrays .binarySearch (sqlErrorCodes .getDeadlockLoserCodes (), errorCode ) >= 0 ) {
266
270
logTranslation (task , sql , sqlEx , false );
267
271
return new DeadlockLoserDataAccessException (buildMessage (task , sql , sqlEx ), sqlEx );
268
272
}
269
- else if (Arrays .binarySearch (this . sqlErrorCodes .getCannotSerializeTransactionCodes (), errorCode ) >= 0 ) {
273
+ else if (Arrays .binarySearch (sqlErrorCodes .getCannotSerializeTransactionCodes (), errorCode ) >= 0 ) {
270
274
logTranslation (task , sql , sqlEx , false );
271
275
return new CannotSerializeTransactionException (buildMessage (task , sql , sqlEx ), sqlEx );
272
276
}
@@ -276,7 +280,7 @@ else if (Arrays.binarySearch(this.sqlErrorCodes.getCannotSerializeTransactionCod
276
280
// We couldn't identify it more precisely - let's hand it over to the SQLState fallback translator.
277
281
if (logger .isDebugEnabled ()) {
278
282
String codes ;
279
- if (this . sqlErrorCodes != null && this . sqlErrorCodes .isUseSqlStateForTranslation ()) {
283
+ if (sqlErrorCodes != null && sqlErrorCodes .isUseSqlStateForTranslation ()) {
280
284
codes = "SQL state '" + sqlEx .getSQLState () + "', error code '" + sqlEx .getErrorCode ();
281
285
}
282
286
else {
0 commit comments