Affects: Spring Framework 5.3.3
When using SimpleJdbcInsert
without usingColumns()
, it tries to determine the columns from database metadata. When there is any exception, a warning is logged, but otherwise the exception is ignored:
https://github.com/spring-projects/spring-framework/blob/91509805b759a108d7eca0b6b3041c434c61d837/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/GenericCallMetaDataProvider.java#L415-L419
This is fine as long as the exception occurs before any metadata could be read, because later this will cause an exception when generating the SQL string:
https://github.com/spring-projects/spring-framework/blob/91509805b759a108d7eca0b6b3041c434c61d837/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/TableMetaDataContext.java#L305-L306
However, when an SQLException
occurs in columns.next()
...
https://github.com/spring-projects/spring-framework/blob/91509805b759a108d7eca0b6b3041c434c61d837/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/GenericCallMetaDataProvider.java#L390
... after the first column metadata has already been read and added to this.callParameterMetaData
, it continues with an incomplete list of columns and only inserts these, ignoring any other columns.
We have experienced this problem in our system very sporadically, and it's especially dangerous, because SimpleJdbcInsert.execute()
(as long as there are no NOT NULL
constraints for the columns) returns seemingly successfully, so the transactions are committed with incomplete/corrupted data.
It seems like we can work around the problem by calling usingColumns()
for all uses of SimpleJdbcInsert
.
Comment From: sbrannen
SimpleJdbcTemplate
no longer exists in Spring Framework 5.3. So I assume you meant to refer to SimpleJdbcInsert
. I've edited this issue's title and description accordingly.
In light of that, did you perhaps mean to provide a link to GenericTableMetaDataProvider
instead of GenericCallMetaDataProvider
?
Or are you using SimpleJdbcCall
instead of SimpleJdbcInsert
?
Comment From: sbrannen
Or are you using
SimpleJdbcCall
instead ofSimpleJdbcInsert
?
In any case, it looks like GenericCallMetaDataProvider.processProcedureColumns(DatabaseMetaData, String, String, String)
and GenericTableMetaDataProvider.processTableColumns(DatabaseMetaData, TableMetaData)
have similar constructs that can result in partial metadata being recorded.
So I'll investigate both.
Comment From: j8zdev
Sorry for the confusion. We're actually using SimpleJdbcInsert and I accidently linked to a similar but wrong line in GenericCallMetaDataProvider
instead of GenericTableMetaDataProvider
. But as you noticed, probably both are affected.
Thanks for investigating!
Comment From: sbrannen
The fix has been merged into master
(5.3.x) and 5.2.x
.
Feel free to try it out in the latest 5.3.4 and 5.2.13 snapshots.