Detailed explanation
Manual transaction management in JDBC means deciding explicitly which database operations succeed or fail together. A new JDBC Connection normally has auto-commit enabled, so each statement is committed individually when it completes. Calling conn.setAutoCommit(false) allows subsequent statements on that connection to participate in a transaction until you call commit() or rollback(). This matters for operations such as transferring money: debiting one account and crediting another must be treated as one unit, rather than leaving a partial update if the second statement fails.
The usual sequence is to obtain a connection, disable auto-commit, execute the related SQL statements, validate their results, and call conn.commit() only when everything succeeds. All statements must use the same connection to belong to the same local transaction. Use PreparedStatement for parameters and check executeUpdate() counts where appropriate; an update affecting zero rows is not automatically an SQL error. In the transfer example, verify that both account updates affect exactly one row and enforce sufficient funds through suitable SQL or locking. Atomicity alone does not make business rules correct under concurrent access.
If an SQLException or relevant application failure occurs before successful completion, attempt conn.rollback() and propagate the original failure instead of silently swallowing it. Rollback can also throw SQLException, so preserve that secondary error, for example with addSuppressed(), rather than replacing the original exception. A connection failure during commit can leave the outcome uncertain from the application's perspective; blindly retrying the transaction could duplicate its effects. The database implements transaction guarantees using mechanisms such as logging, locks, and multiversion concurrency control, depending on the engine and isolation level.
Resource and connection-state cleanup are equally important. Close statements and result sets with try-with-resources, and ensure the transaction is resolved before closing or returning the connection to a pool. Restore the previous auto-commit setting when reusing a connection, but do not switch it to true while an unresolved transaction remains: that change can commit pending work. For a broken connection, follow the pool's invalidation mechanism. Interviewers look for explicit transaction boundaries, reliable rollback handling, resource cleanup, and awareness that transactional support and implicit commits, especially around DDL, depend on the database.
Key points to remember
- Call setAutoCommit(false) before executing the operations that must form one transaction.
- Execute all participating statements on the same Connection and validate required update counts.
- Call commit() only after every operation and business validation succeeds.
- Attempt rollback() on failure, propagate the original exception, and preserve rollback errors.
- Close resources and restore reusable connection state only after resolving the transaction.
Common mistakes candidates make
- Swallowing the original exception after rollback, making a failed operation appear successful.
- Assuming zero-row updates throw exceptions or that atomicity alone prevents concurrency problems.
- Setting auto-commit back to true in an unconditional finally block even when rollback failed, risking a commit of pending work.
Likely follow-up questions
Can you roll back only part of a JDBC transaction?
Yes, if the database and driver support savepoints, create one with conn.setSavepoint() and use conn.rollback(savepoint) to undo subsequent work. Earlier work remains pending, and you must still commit or roll back the overall transaction.
How does transaction isolation differ from atomicity?
Atomicity makes a transaction's changes succeed or fail together, while isolation governs interactions between concurrent transactions. Configure supported isolation levels with setTransactionIsolation(), preferably before starting transactional work.
Does closing a Connection automatically roll back its transaction?
Do not rely on it: JDBC specifies that closing a connection with an active transaction has implementation-defined results. Explicitly commit or roll back before closing it; pooled connections also require safe state cleanup before reuse.
Interview tip: Explain the disable–execute–validate–commit flow first, then mention rollback, same-connection scope, and safe cleanup.
