Repository navigation
ADR 001 Deferred Bind ConnectionProvider
Accepted
The audit trigger framework (V1.0.5) writes complete OLD/NEW JSONB row images into hrs.audit_event and hrs.audit_change. To support distributed tracing correlation, the B3 trace ID from the current Micrometer span must be captured into audit_event.correlation_id without introducing AOP, request filters, or application ThreadLocal state.
PostgreSQL GUCs set with set_config('app.correlation_id', ?, true) are transaction-local — they are discarded on commit/rollback and do not bleed into subsequent transactions on pooled connections. The challenge is when to execute the set_config statement: Hibernate acquires the JDBC connection before applying the caller's transaction isolation level.
The project uses SERIALIZABLE isolation on service methods. Any statement executed during connection acquisition opens the PostgreSQL transaction block first, making a subsequent SET TRANSACTION ISOLATION LEVEL SERIALIZABLE fail with:
PSQLException: Cannot change transaction isolation level in the middle of a transaction
Use a deferred-bind ConnectionProvider decorator (CorrelationIdConnectionProvider) that wraps the pooled connection in a DeferredCorrelationIdConnection. The wrapper executes SELECT set_config('app.correlation_id', ?, true) lazily — immediately before the first statement-producing call (createStatement, prepareStatement, prepareCall, or setSavepoint), not at connection acquisition time.
This ordering ensures the GUC binding lands after Spring has applied transaction isolation, inside whatever transaction Spring/Hibernate established.
Additionally, pool-wide spring.datasource.hikari.auto-commit=false is required so that set_config(..., true) executes inside an active transaction block (autocommit-on single statements never have one).
- No AOP, no request filter, no application
ThreadLocal— minimal surface area. - GraalVM/native-image safe: no reflection, no proxies, no runtime bytecode.
- Transaction-local GUC (
trueargument) eliminates need for explicit reset bookkeeping. - Works with Hibernate's default
DELAYED_ACQUISITION_AND_RELEASE_AFTER_TRANSACTIONconnection handling mode.
- The
DeferredCorrelationIdConnectionwrapper implements the fulljava.sql.Connectioninterface (464 lines) — every method must forward correctly. - Pool-wide
auto-commit=falsechanges the default connection behavior for all Hibernate operations. - The
HibernatePropertiesCustomizerbean uses deprecatedDatasourceConnectionProviderImplAPIs (@SuppressWarnings({"deprecation", "removal"})) — intentional and must not be simplified to bean-container SPI.
- Native-image compilation and runtime validation were not run during the spike. Follow-up validation required.
- The
set_configcost per connection acquisition should be measured if connection handling changes.
Execute setAutoCommit(false) + set_config directly in getConnection(). Rejected: opens the transaction block before Spring applies isolation, breaking every SERIALIZABLE service method.
Intercept service methods and set the GUC after transaction setup. Rejected: introduces AOP proxy complexity, breaks for self-invocation, and is not GraalVM-safe without additional configuration.
Set the GUC in an HTTP filter. Rejected: filters execute before the transaction begins; the GUC would be session-scoped and could bleed across requests on pooled connections.
Use set_config(..., false) (session-scoped) and reset in closeConnection(). Rejected: leaks state on any missed close path; the deferred-bind design with transaction-local GUC is strictly safer.
Hibernate's LazyConnectionDataSourceProxy buffers statements until first use. Rejected: does not solve the isolation-level ordering problem; the proxy still opens the transaction before the caller's isolation is applied.
- GraalVM native-image compilation and runtime validation
- Measure
set_configcost per connection acquisition - V1.0.6 adds or guards
correlation_id, creates a partial lookup index, and reads the GUC withcurrent_setting('app.correlation_id', true). Existing V1.0.5 databases retain the effectiveVARCHAR(128)width; any narrowing requires a separate reviewed migration.
This wiki documents NR Waste Plus for users and developers. Verify security and deployment guidance against the current application configuration before applying it elsewhere.
- Report an issue or ask a question in the GitHub repository.
- Follow the Contributing Guidelines to propose an update.
- Read the Code of Conduct.
Collection indexes support human browsing and machine retrieval. Keep both current when adding or moving wiki pages.
NR Waste Plus Wiki | GitHub Repository