To coordinate a critical section across multiple Spring Boot instances, acquire a PostgreSQL transaction-level advisory lock and run the protected database work in the same Spring-managed transaction. Every relevant caller must use the same key and lock convention: PostgreSQL does not make other application code honor an advisory lock automatically.
Why a shared database lock can help
A Java monitor or other in-process lock can coordinate threads inside one JVM, but it cannot coordinate separate Spring Boot instances. PostgreSQL advisory locks can provide a shared coordination point for callers using the same database, provided every relevant code path cooperates.
As an Amazon Associate I earn from qualifying purchases.
PostgreSQL describes advisory locks as locks with application-defined meanings. The application decides what a key represents and which work must acquire it. They can help protect application-defined critical sections that are awkward to express with row locks, but they do not replace database constraints or ordinary locking when those already protect the required invariant.
Choose the right database guarantee
Start by identifying the invariant, not by choosing a lock API. If the requirement is that a value remain unique or that a row not be changed concurrently, a uniqueness constraint or ordinary row-level lock may express the rule more directly. PostgreSQL notes that proper use of MVCC generally provides better performance than locks.
#1 Best Overall
- Constraints: Use a database constraint when the invariant can be enforced by the data model, such as uniqueness.
- Row locks: Use ordinary row-level locking when competing work concerns particular rows.
- Advisory locks: Consider these for an application-defined critical section that does not map neatly to a particular row lock, and make sure all relevant writers can be made to cooperate.
Advisory locks do not prevent a caller that ignores the convention from changing the same data. Nor do they eliminate transaction contention or deadlocks.
Keep lock acquisition and protected SQL in one Spring transaction
For a short database critical section, use a transaction-level lock. It is released automatically when its transaction ends, whether the transaction commits or rolls back. With Spring JDBC, run the lock acquisition and the protected operations within the same intended Spring-managed transaction. JdbcTemplate participates in an ongoing Spring transaction through Spring-aware connection access.
For example, the SQL function for a transaction-level lock using a single bigint key is pg_advisory_xact_lock(bigint). A call that waits for the lock can be issued as SQL such as SELECT pg_advisory_xact_lock(?);; bind the application’s stable key as the parameter. Once that call succeeds, perform the protected database work before the same transaction completes.
Recommended Free Tools
Rank #2
@Transactional
public void processResource(long lockKey) {
jdbcTemplate.queryForObject(
"SELECT pg_advisory_xact_lock(?)",
Long.class,
lockKey
);
// Perform the protected database operations with jdbcTemplate here.
}
This example assumes the method is invoked through Spring’s transaction management and that the relevant transaction manager manages the same data source used by JdbcTemplate. Check the exact Spring Boot, Spring Framework, JDBC driver, and PostgreSQL versions in your application before adopting code or configuration.
If using direct JDBC instead of JdbcTemplate, obtain the connection through Spring’s supported transaction-aware mechanisms, such as DataSourceUtils. Opening an unrelated connection can put the lock and the protected work in different transactions, defeating the intended coordination.
Use transaction scope unless session lifetime is deliberate
PostgreSQL offers transaction-level and session-level advisory locks, and their cleanup behavior differs materially.
Rank #3
| Lock scope | Release behavior | Operational implication |
|---|---|---|
| Transaction-level | Released automatically when the transaction ends; there is no explicit unlock function. | Fits a short critical section contained in one transaction. |
| Session-level | Persists until explicitly unlocked or the database session ends; rollback does not release it. | Can be retained unexpectedly when a pooled connection is reused. Repeated acquisition by the owning session requires matching unlock calls. |
Prefer transaction-level locks unless the application intentionally manages lock lifetime at the session level. A pooled connection may outlive the request or transaction that acquired a session-level lock, so careless cleanup can leave subsequent work unexpectedly blocked.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Make keys stable and unambiguous
PostgreSQL supports advisory-lock keys as either one bigint or a pair of integer values. Define and document a stable mapping from the protected resource or task identity to one of these shapes. Every participating instance must derive the same key for the same work.
- Use a clear namespace/key convention when unrelated domains could otherwise share values.
- Ensure all callers use the same lock scope and compatible lock operation for a given protected resource.
- Remember that advisory locks are local to a PostgreSQL database. Separate databases do not coordinate through the same advisory-lock namespace, even if hosted by the same PostgreSQL cluster.
Keep the critical section short and on the transaction’s execution context
Do not hold a database lock while waiting for user input or doing unrelated slow work. A longer transaction keeps the lock for longer and can increase contention.
In imperative Spring transaction handling, the JDBC transaction is bound to the executing thread. Work sent to a newly started thread does not automatically inherit the transaction, so a lock acquired in one thread will not safely cover database operations performed through a separate transaction in another.
Reactive transactions use different context rules. Use the reactive transaction manager and keep participating data-access operations in the same Reactor context rather than assuming imperative thread-bound behavior applies.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsPlan for deadlocks and retries
Advisory locks can participate in deadlocks just like other locks. If an operation needs multiple locks, acquire them in a consistent order across callers. Handle deadlock or serialization failures intentionally, and retry only when the complete operation—including any application-level side effects—is safe to repeat.
PostgreSQL keeps lock state in shared memory, with capacity governed by max_locks_per_transaction and max_connections. Applications that take very high numbers of locks can exhaust the lock pool, so do not assume advisory locks are an unlimited coordination mechanism.
Inspect lock waits in PostgreSQL
Use pg_locks to inspect held and awaited advisory locks, then relate the lock process ID to pg_stat_activity to see session and query context. Check whether the lock is granted or awaited, which database owns it, and what transaction or query is associated with the process. A brief wait can be normal; an unexpectedly long wait is a reason to investigate transaction duration and whether callers use the same key convention.
SELECT a.pid,
a.datname,
a.state,
a.wait_event_type,
a.wait_event,
a.query,
l.locktype,
l.classid,
l.objid,
l.objsubid,
l.granted
FROM pg_locks AS l
JOIN pg_stat_activity AS a ON a.pid = l.pid
WHERE l.locktype = 'advisory';
For advisory locks, the key representation appears in PostgreSQL’s lock-view columns; interpret those fields using the PostgreSQL documentation for the server version in use. Joining by process ID provides useful session context, but it does not by itself explain the application’s key mapping, which should be documented alongside the code.
Avoid surprising lock acquisition in ordered queries
Be careful when calling advisory-lock functions in a query that also uses ORDER BY and LIMIT. PostgreSQL warns that expression evaluation order can lead to locks being acquired for rows beyond those you intended to select. When necessary, isolate the selected rows in a subquery before applying the lock call.
Quick Recap
PostgreSQL references
- PostgreSQL 17: Explicit Locking — Advisory Locks
- PostgreSQL 18: pg_locks
- Spring Framework: JDBC connections
- Spring Framework: Understanding the Spring transaction abstraction
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




