Class JdbcIdempotencyRepository
- All Implemented Interfaces:
IdempotencyRepository
IdempotencyRepository backed by any JDBC-compatible database.
This class has zero framework dependencies: it uses only
java.sql.* from the JDK and is usable from Spring Boot, Quarkus, Micronaut,
JAX-RS, or plain Java. Framework-specific wiring (e.g., Spring Boot auto-configuration)
is handled by the idempotency-spring-boot-starter module.
Supported databases
- PostgreSQL —
INSERT … ON CONFLICT DO NOTHING - MySQL / MariaDB —
INSERT IGNORE … - H2 —
INSERT IGNORE … - Any other JDBC driver — plain
INSERT, duplicate-key detected via SQLState23xxx
Atomicity
The acquireOrGet(String) method uses an optimistic insert as the distributed
lock primitive: the first caller to INSERT a STARTED row wins the lock;
concurrent callers receive a duplicate-key signal from the database (mapped to
IdempotencyConflictException).
Header serialisation
Response headers (Map<String, List<String>>) are persisted as a compact plain-text
string requiring no external libraries. Format: name=v1|v2;name2=v3. Values containing
;, =, or | are percent-encoded.
Usage (non-Spring)
DataSource ds = ...; // your connection pool
new JdbcIdempotencyTableInitializer().initialize(ds); // one-time DDL
IdempotencyRepository repo = new JdbcIdempotencyRepository(ds, new IdempotencyConfig());
IdempotencyManager manager = new IdempotencyManager(repo);
-
Constructor Summary
ConstructorsConstructorDescriptionJdbcIdempotencyRepository(DataSource dataSource, IdempotencyConfig config) Constructs a JDBC-backed repository using the supplied data source and configuration. -
Method Summary
Modifier and TypeMethodDescriptionacquireOrGet(String idempotencyKey) Delegates toacquireOrGet(String, String)with anullhash.acquireOrGet(String idempotencyKey, String requestHash) Atomically acquires a distributed lock or returns an existingCOMPLETEDrecord.voidRemoves the idempotency record associated with the given key.intEvicts all expired records from the underlying storage.Pure read-only check of the current record.voidsaveFailure(String idempotencyKey, String errorMessage) Clears the active lock and updates the state to FAILED.voidsaveSuccess(String idempotencyKey, IdempotencyResponse response) Updates an existing record with a successful payload and sets the state to COMPLETED.
-
Constructor Details
-
JdbcIdempotencyRepository
Constructs a JDBC-backed repository using the supplied data source and configuration.- Parameters:
dataSource- the JDBC data source used to access the idempotency tableconfig- the idempotency TTL and lock-timeout settings
-
-
Method Details
-
acquireOrGet
Delegates toacquireOrGet(String, String)with anullhash.- Specified by:
acquireOrGetin interfaceIdempotencyRepository- Parameters:
idempotencyKey- The unique key for the request.- Returns:
- An optional containing the existing record if it's completed, or an empty optional if a new lock was acquired.
-
acquireOrGet
Atomically acquires a distributed lock or returns an existingCOMPLETEDrecord.Algorithm:
- Attempt
INSERTof aSTARTEDrow. - If the insert succeeds (1 row affected) → lock acquired, return
empty(). - If the insert fails (0 rows / duplicate key) →
SELECTthe existing row and:COMPLETED: validate hash, return the record for replay.STARTED, not expired: throwIdempotencyConflictException.STARTED, expired ORFAILED: delete stale row and re-insert.
- Specified by:
acquireOrGetin interfaceIdempotencyRepository- Parameters:
idempotencyKey- The unique key for the request.requestHash- The hash of the request payload to ensure the key is not reused for a different payload.- Returns:
- An optional containing the existing record if it's completed, or an empty optional if a new lock was acquired.
- Attempt
-
saveSuccess
Description copied from interface:IdempotencyRepositoryUpdates an existing record with a successful payload and sets the state to COMPLETED.- Specified by:
saveSuccessin interfaceIdempotencyRepository- Parameters:
idempotencyKey- The unique key for the request.response- The response to save.
-
saveFailure
Description copied from interface:IdempotencyRepositoryClears the active lock and updates the state to FAILED. Usually implies the request can be retried by the client.- Specified by:
saveFailurein interfaceIdempotencyRepository- Parameters:
idempotencyKey- The unique key for the request.errorMessage- The error message to save.
-
get
Description copied from interface:IdempotencyRepositoryPure read-only check of the current record.- Specified by:
getin interfaceIdempotencyRepository- Parameters:
idempotencyKey- The unique key for the request.- Returns:
- An optional containing the record if found, empty otherwise.
-
delete
Description copied from interface:IdempotencyRepositoryRemoves the idempotency record associated with the given key. Useful for administrative cleanup or explicit invalidation.- Specified by:
deletein interfaceIdempotencyRepository- Parameters:
idempotencyKey- The unique key to remove.
-
evictExpired
public int evictExpired()Description copied from interface:IdempotencyRepositoryEvicts all expired records from the underlying storage. Useful for periodic cleanup in persistent data stores.- Specified by:
evictExpiredin interfaceIdempotencyRepository- Returns:
- The number of records deleted.
-