Skip to content

save cannot distinguish no-op updates from failed updates #2209

@ryanmurf

Description

@ryanmurf

Environment

  • Spring Boot: 4.0.0
  • Spring Data JDBC: 4.0.0
  • Database: Postgres 18.1

Description

I was updating from 4.0.0 to 4.0.1 and noticed a behavior change.

I’m concerned this change introduces ambiguous success semantics for save() when the underlying UPDATE affects 0 rows.

I understand the motivation: some databases (e.g., MySQL) can legitimately report 0 affected rows when an entity is saved with values identical to what’s already stored, even though the row exists. That makes throwing IncorrectUpdateSemanticsDataAccessException in that case undesirable.

However, treating 0 updated rows as success also collapses other important cases into the same outcome:

  • Missing row / stale ID: an UPDATE … WHERE id = ? that matches nothing also returns 0. Previously, the exception made it clear no row was actually updated. Now save() appears to succeed even though nothing happened.

  • Row-Level Security / policy-based updates: with RLS (or similar update policies), the row may exist but the user is not permitted to update it; postgres will still report 0 affected rows. In that case, returning successfully makes it look like the update was applied when it was not.

In other words, 0 rows updated is inherently ambiguous: it can mean no-op update or update didn’t apply. Relying on the update count/exception is currently the only way to detect whether a change was actually applied.

Would it be possible to make this behavior configurable or dialect-specific, or to disambiguate the 0 rows case (e.g., by checking existence when UPDATE returns 0, or providing an opt-in mode that preserves the previous exception behavior)?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions