Deadlocks in JDBC typically refer to database-level deadlocks, where two or more transactions block each other while waiting for locks on resources (e.g., rows or tables). JDBC itself doesn’t “detect” them proactively; instead, the database server signals them via exceptions. Here’s how to handle detection effectively:
1. Catch and Inspect SQLException
Wrap your JDBC operations (e.g., executeUpdate(), executeQuery()) in a try-catch block. When a deadlock occurs, the database driver throws an SQLException. Check its properties to confirm it’s a deadlock:
- SQLState: A standard code (e.g., starts with “40” for serialization failures like deadlocks in many databases).
- Error Code: Vendor-specific (e.g., database-dependent numbers).
- Message: Often contains keywords like “deadlock” or “lock wait timeout”.
Example in Java:
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public void performDatabaseOperation(Connection conn) {
try (PreparedStatement stmt = conn.prepareStatement("UPDATE table SET column = ? WHERE id = ?")) {
stmt.setString(1, "value");
stmt.setInt(2, 1);
stmt.executeUpdate();
} catch (SQLException e) {
if (isDeadlock(e)) {
// Handle deadlock: e.g., retry the transaction or log it
System.out.println("Deadlock detected: " + e.getMessage());
// Optional: retry logic here
} else {
throw new RuntimeException("Database error", e);
}
}
}
private boolean isDeadlock(SQLException e) {
String sqlState = e.getSQLState();
int errorCode = e.getErrorCode();
// Common checks (adapt to your database)
if (sqlState != null) {
if (sqlState.startsWith("40")) { // General serialization failure (deadlock/timeout)
return true;
}
}
// Database-specific error codes
// MySQL example: Deadlock (1213) or lock wait timeout (1205)
if (errorCode == 1213 || errorCode == 1205) {
return true;
}
// PostgreSQL example: 40P01 for deadlock
// Oracle example: ORA-00060 (error code 60)
return false; // Not a deadlock
}
2. Database-Specific Detection
Error codes vary by database—always check your DBMS docs for exact values:
- MySQL: Error code 1213 (deadlock) or 1205 (lock wait timeout). SQLState “40001” or “HY000”.
- PostgreSQL: SQLState “40P01”.
- Oracle: Error code 60 (ORA-00060).
- SQL Server: Error code 1205.
If using Spring Data JPA (from your project stack), exceptions are wrapped in DataAccessException subclasses like ConcurrencyFailureException. You can catch those for higher-level handling.
3. Prevention and Retry Strategies
- Use Transactions Wisely: Keep them short, use appropriate isolation levels (e.g.,
READ_COMMITTEDviaconn.setTransactionIsolation(...)). - Retry Logic: For transient deadlocks, retry the entire transaction (e.g., 2-3 times with exponential backoff). Ensure operations are idempotent.
- Monitoring: Enable database logging or use tools like Java’s ThreadMXBean for thread-level deadlocks (unrelated to DB), but for DB deadlocks, rely on JDBC exceptions.
