JDBC is the Java API boundary for database access.
You will connect a matched driver and configured data source to prepared statements, result sets, update counts and transaction decisions.
The examples are backendJava fragments; uploading them to a static frontend does not execute SQL.
The lab transfers fictional practice tokens between two local learners.
It compares one transaction with statement-by-statement auto-commit and shows a failure after the debit.
This synchronous JavaScript model runs no Java, database, driver or network connection.
🔌
Connect
Separate API, driver, data source and database.
🔑
Bind
Keep values separate from SQL structure.
📋
Read
Map result rows and check update counts.
🔄
Transact
Explain commit, rollback and owned resources.
02
🔌API, Driver and Database Have Different Jobs
JDBC defines Java interfaces such as Connection, PreparedStatement and ResultSet.
A compatible JDBC driver implements the database-specific communication.
The database stores data and executes supported SQL; JDBC is not itself a database engine.
A project needs the driver dependency, a reachable database and correct server configuration.
A java.sql import does not install a driver or create a schema.
A JDBCURL format and supported features depend on the chosen database and driver.
Modern drivers can be discovered through service-provider loading when installed correctly.
Older examples may explicitly load a driver class.
Follow the actual driver’s setup rather than assuming one class name works for every product.
Database access boundary
☕Application
Uses Javadatabase interfaces.
🔌JDBC driver
Communicates with the chosen database.
🗃️Database
Executes SQL and enforces constraints.
📋Java model
Receives checked application values.
This lesson adds frontend teaching files only. No backend database or credential is created by the patch.
03
🧰DriverManager and DataSource
DriverManager can open a connection using a suitable JDBCURL and connection properties.
DataSource provides a connection-factory abstraction that application configuration can supply, including pool-backed implementations.
They are different entry points into the same JDBC work.
In a web application, a configured data source keeps connection setup separate from controller and repository logic.
Store credentials in protected backend configuration, not browser JavaScript, a public ZIP, source comments or a JSP page.
javax.sql.DataSource remains a Java platform API.
Modern jakarta.servlet imports do not require mechanically renaming it to jakarta.sql.
A data source abstraction does not guarantee that pooling has been configured.
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
// dataSource is supplied by protected backend configuration.
try (Connection con = dataSource.getConnection()) {
// Prepare and execute database work here.
}
A pooled connection close normally releases the logical connection back to its pool.
Check the pool’s contract for validation, reset and failure disposal; do not assume every DataSource has identical behavior.
04
📦Connection Ownership and Resource Lifetimes
A Connection represents a databasesession.
Statements and result sets are associated with it and have their own resource lifetimes.
Close the resources your code owns instead of depending on garbage collection or a final servlet shutdown callback.
Try-with-resources closes resources in reverse declaration order and records additional closing failures as suppressed exceptions.
Nest a result set inside the statement and connection lifetime so the mapper cannot read rows from an already closed resource.
Do not keep one mutable Connection as a shared servlet field for all callers.
Request handling, transaction ownership and thread safety require deliberate boundaries.
A repository receiving a caller-owned connection should not close it unexpectedly.
Close owned resources
🔌Connection
Owns the databasesession boundary.
🔑Statement
Owns SQL execution resources.
📋Result set
Owns a row cursor/result resource.
🧹Cleanup
Close result, statement, then connection.
The lab exposes mock opened/closed counts.
These are teaching counters, not evidence of real connection-pool, driver or cleanup behavior.
05
🔑Prepared Statements Bind Values
Create a prepared statement with a fixed SQL structure and bind values to question-mark placeholders.
JDBC parameter positions start at one.
Choose suitable setters for the database/application type and bind every required parameter.
A bound value remains a value.
It does not become a table name, column name, sort direction or arbitrary SQL fragment.
If a query supports dynamic structure, choose that structure from an application-controlled allowlist rather than treating a placeholder as an identifier.
Prepared statements address separation of values from SQL syntax.
They do not replace input validation, authorization, transaction rules or safe output rendering.
The snippet assumes an open caller-owned con and a validated identifier.
It is not a complete repository or database schema.
The lab shows fixed SQL plus a separate binding panel; it never interpolates submitted text into executable SQL.
06
📤Choose the Execution Method
executeQuery is used when the statement produces a result set. executeUpdate returns an update count for relevant data-changing statements; an operation that changes no matching row can legitimately return zero. execute handles cases where the result kind needs to be inspected.
Do not read executeUpdate’s return value as an automatically generated row ID.
Generated keys use their own statement configuration and result retrieval, with driver/database support.
Multiple results and batches have additional API contracts.
For the token transfer, a conditional debit must affect exactly one row.
A zero debit count means this operation was not accepted, such as insufficient tokens or a missing source; the credit must not run.
📋
executeQuery
Read a ResultSet for a query.
✏️
executeUpdate
Inspect the affected-row count.
🧭
execute
Inspect the returned result kind.
🔢
Generated keys
Use the appropriate separate API.
int changed = debit.executeUpdate();
if (changed != 1) {
throw new java.sql.SQLException("Debit was not accepted");
}
// Only then attempt the paired credit.
This application expects one affected row.
Other operations need their own deliberate count contract rather than assuming every successful update returns one.
07
📋ResultSet Cursors and Row Mapping
A ResultSet cursor begins before the first row.
Call next to advance and test whether a row exists before reading columns.
A forward-only result is not a collection that you can randomly index or repeatedly rewind.
Read columns by an intentional label or index and map them into an application model.
Validate the required shape, ranges and nullability.
Do not pass a live result set to the JSP and let the view depend on a database cursor remaining open.
Primitive getters need attention to SQLNULL: getInt can return zero for null and wasNull can distinguish it immediately after the read.
A zero count and an absent database value may have different meanings.
try (java.sql.ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
String id = rs.getString("learner_id");
int tokens = rs.getInt("tokens");
if (rs.wasNull()) {
throw new java.sql.SQLException("Missing required tokens");
}
// Check id and tokens, then create an application value.
}
}
Use a nullable Java representation when null is allowed by the contract.
For exact monetary decimal values, choose a suitable decimal database/Java type rather than assuming binary floating-point is exact.
The lab uses bounded integer practice tokens, not money.
08
🧱Repository Boundaries and Schema Assumptions
A repository or DAO contains SQL details and row mapping behind an application boundary.
A service coordinates operations, and a controller validates request values and chooses the response.
A JSP should render the accepted model rather than run SQL or own transaction cleanup.
The transfer illustration assumes a practice_tokens table with a unique learner_id and non-negative integer tokens.
Database constraints, authorization and transaction support must exist in the real implementation; the local model does not create those protections on a server.
The toy fixture starts with A = 12 and B = 4.
Learner identifiers are exactly A or B.
Amount is a canonical integer string from 1 to 9, and source must differ from destination.
DDL syntax and constraint enforcement depend on the database.
Level 26 develops database design and SQL further; this lesson focuses on the Java access boundary.
09
⚡Auto-Commit and Partial Operations
A newly created JDBC connection defaults to auto-commit.
In that mode, statement completion commits its transaction; completion rules depend on the statement/result type.
Two successful updates are not automatically one atomic application operation.
If a debit commits and the following credit fails, the earlier committed debit is not undone by rolling back a later transaction.
The caller has a partial outcome and needs a deliberate recovery strategy; retrying blindly can make the situation worse.
The lab’s auto-commit mode publishes the debit immediately.
A simulated credit error or zero-row credit then returns 500 while keeping the partial debit visible.
The earlier committed snapshot is not silently restored.
One operation, different boundaries
➖Debit
Change the source tokens.
⚡Auto-commit
Debit is already published.
⚠️Credit failure
The paired update does not finish.
📉Partial result
Earlier debit remains committed.
The model simplifies two update statements and their outcomes.
It does not represent all JDBC result-completion rules or distributed failures.
10
🔄One Transaction: Commit or Roll Back
Disable auto-commit deliberately when one application operation needs multiple statements in a transaction.
Execute both updates on the same owned connection and call commit only after both satisfy the application’s update-count contract.
On a failure before commit, attempt rollback and propagate the failure.
Rollback can itself fail.
Preserve the original error and record the cleanup failure instead of pretending the operation is known to be undone.
The lab’s manual transaction holds a separate working copy.
A successful credit publishes both updates together; a known simulated credit failure discards the working copy and leaves the prior committed snapshot unchanged.
// Illustrative owned-connection transaction fragment.
// Inputs were validated; dataSource and statement helper are supplied.
try (java.sql.Connection con = dataSource.getConnection()) {
con.setAutoCommit(false);
try {
// Execute debit and credit on THIS connection.
// Require the expected affected-row count for each.
performTransferStatements(con, fromId, toId, amount);
con.commit();
} catch (java.sql.SQLException | RuntimeException failure) {
try {
con.rollback();
} catch (java.sql.SQLException rollbackFailure) {
failure.addSuppressed(rollbackFailure);
}
throw failure;
}
}
The helper is defined by the surrounding repository; this is a fragment, not a complete compilable application.
It owns the acquired connection and closes it after resolution.
Pool state reset/disposal belongs to the configured connection contract.
Do not re-enable auto-commit to hide an unresolved transaction: changing that mode can commit outstanding work.
11
🧮Conditional Updates and Count Checks
The debit statement can require both a matching source identifier and enough tokens in its WHERE clause.
That avoids a simplistic read-then-write check in application code, but real concurrency, isolation and database behavior still need testing.
Bind the amount twice in the debit: once for subtraction and once for the minimum check.
Then bind the credit amount and destination separately.
Only an accepted debit allows the credit to proceed.
A credit affecting zero rows is not a successful paired transfer in this contract.
In a manual transaction, treat it as a failure and roll back the debit.
In auto-commit, the already committed debit remains partial.
UPDATE practice_tokens
SET tokens = tokens - ?
WHERE learner_id = ? AND tokens >= ?
Debit bindings: 1 = amount, 2 = fromId, 3 = amount
UPDATE practice_tokens
SET tokens = tokens + ?
WHERE learner_id = ?
Credit bindings: 1 = amount, 2 = toId
The local model checks these decisions synchronously against its own integers.
It does not prove atomic SQL predicates, lock behavior or concurrent transfers in a real database.
12
🧵Isolation, Savepoints and Concurrent Work
A transaction boundary and a transaction isolation level solve related but different problems.
Isolation controls which effects of concurrent work can be observed.
Supported levels and behavior vary with the driver/database; do not infer them from a synchronous browser demonstration.
Some drivers/databases support savepoints for partial rollback within a transaction.
A savepoint is not a separate permanent commit and is not a universal substitute for rolling back an operation whose invariants failed.
Keep transactions short and avoid waiting for user interaction while holding database resources.
Design a consistent update order and a deliberate retry policy for recognized transient conflicts.
A retry must consider whether an earlier attempt actually committed.
🔄
Atomicity
Treat paired statements as one accepted unit.
🧵
Isolation
Account for simultaneous database work.
📍
Savepoint
A supported rollback position within a transaction.
⏱️
Timeout/retry
Use driver/database-aware bounded policies.
The lab has no locks, threads, savepoints, deadlocks or retries. Those runtime behaviors remain separate integration checks.
13
⚠️Errors and Uncertain Outcomes
SQLException provides database failure information, including SQLState, a vendor code and chained exceptions.
Backend diagnostics can retain those details; public responses should avoid leaking credentials, SQL internals or production stack traces.
A stable error response should not claim success merely because the first statement ran.
In this lab an insufficient debit returns 409, an unavailable fixture 503 and a failed credit 500.
A connection loss or timeout around commit can leave the client unsure whether the database committed.
Do not claim rollback always proves nothing happened.
A real system needs a recovery/idempotency strategy appropriate to its operation.
📨
Invalid input
Reject before acquiring a connection.
🔌
Unavailable
No mock connection is opened.
➖
Zero debit
Do not execute the credit.
⚠️
Commit uncertainty
Verify/recover instead of blindly retrying.
The lab deliberately models only known outcomes before commit.
Its failure fixture always knows the credit did not apply.
It does not simulate commit ambiguity or rollback failure.
14
📦Pools, Configuration and Deployment
Configure a driver and data source on the backend, with appropriate credentials, network access, limits and connection validation.
A pool can reuse physical connections, but exhausted pools, stale sessions and leaked resources still need monitoring.
Borrow a connection for its intended operation and resolve the transaction before returning it.
The pool must have a deliberate reset/disposal strategy so a later borrower does not inherit unexpected transaction state.
Do not copy a local databaseURL or password into the public frontend to make browser JDBC work.
Browser code calls an authorized backend API; that backend owns JDBC work and decides what accepted model to expose.
Keep credentials on the backend
🪟Frontend
Sends an allowed application request.
🛂Controller/service
Validates and authorizes.
🗃️Repository
Owns JDBC operations.
🔌Configured data source
Supplies backend connections.
This course patch does not modify the Render tracers or add a JDBCbackend. Its resource counters are local model data only.
15
🧪Test Logic and Real JDBC Separately
Test input normalization, update-count decisions, transaction outcome and resource ownership with controlled fixtures.
Then test the actual Java component with the chosen database/driver, schema constraints, transaction support, isolation and error handling.
For paired transfers, test successful commit, insufficient source, zero-row credit and an execution failure after the debit.
Check the persisted database state after each case rather than trusting a success message or log line alone.
A JavaScript token model can verify its own snapshots, invariants and reset behavior.
It cannot compile Java, validate a driver, open JDBC connections or demonstrate real rollback, concurrency and pool cleanup.
✅
Success
Paired transfer preserves the operation’s token total.
↩️
Known failure
Manual mode retains the earlier committed snapshot.
📉
Partial outcome
Auto-commit reveals the committed debit.
🧩
Integration
Check actual database state and resource behavior.
Use the visualizer for an accepted manual transaction, then change the lab’s mode and credit outcome to predict the difference.
Level 26 continues with Databases and SQL for Web Applications.
16
🔄Premium Visualizer — An Accepted JDBC Transaction
Trace a fictional token transfer through validation, connection acquisition, bound debit/credit updates, commit and cleanup. This approved five-stage player explains one accepted manual transaction without running Java or SQL.
JDBC TRANSACTION TRACE
Step 1 of 5
📨
STEP 01
Accept the transfer operation
Validate distinct learner IDs and a bounded canonical integer amount.
A → B · amount 3
What is happening?
Rejected input stops before connection acquisition.
17
🧪Premium Interactive — Commit, Rollback and Partial Transfer
Transfer fictional integer practice tokens between A and B.
Initially A has 12 and B has 4.
This is a synchronous JavaScript model, not Java, JDBC, SQL execution, a database or a financial account.
Results persist only in this tab’s in-memory fixture until Reset.
POST /transfer accepts exactly from, to and amount as scalar strings.
IDs must be A/B and distinct; amount must be exactly one canonical digit 1–9.
Rejection occurs before mock connection acquisition.
The fixed SQL and bindings are displayed separately.
Manual transaction: stage debit and credit, then publish both together.
A known credit error or zero-row credit rolls back the staged debit.
Auto-commit: publish each statement; a failed credit leaves the earlier debit committed.
Insufficient source returns 409 and no credit runs.
The unavailable fixture returns 503 before opening resources.
Opened/closed resource counts belong to the current demonstration run, not a real driver or pool.
The working snapshot shows attempted changes, while committed state shows what remains afterward.
No concurrency, rollback failure or uncertain commit is simulated.
Idle. JavaScript model; no database is connected.
Current committed mock balances
Fixed statement structure and separate bindings
No accepted bindings yet.
Operation trace and mock cleanup
No operation yet.
Before, attempted working state and committed after
No transfer attempted.
Current run resource counts and affected rows
No resources opened.
Simulated response
No response yet.
Outcome summary · safe text
No result yet.
18
🛠️Debugging — Check Counts, State and Ownership
🔑
Bindings
Match every one-based placeholder and setter type.
📋
Result cursor
Call next before reading; distinguish null from zero.
🔄
Transaction
Check the same connection owns both updates.
🧹
Resources
Resolve the operation and close owned resources.
If the debit succeeds but tokens disappear on a credit failure, check whether auto-commit published it independently.
If a missing destination still reports success, inspect the credit update count.
If no source was affected, stop before executing the paired credit.
If database connections run out, inspect borrowed connections, unclosed statements/results, long transactions and pool settings.
A browser teaching counter cannot diagnose a real leak.
If a timeout occurs around commit, report the uncertainty and use a deliberate verification/recovery policy.
Do not infer that the database rolled back simply because the client received an exception.
19
💬Interview Questions — Flip to Explain
QUESTION
Is JDBC itself a database engine?
Click or press Enter to explain
ANSWER
No. JDBC defines Java database-access APIs; a driver communicates with the actual database.
QUESTION
Does every DataSource provide pooling?
Click or press Enter to explain
ANSWER
No. DataSource is an abstraction; the configured implementation and environment determine pooling behavior.
QUESTION
Why bind values in a prepared statement?
Click or press Enter to explain
ANSWER
To keep supplied values separate from fixed SQL structure. Validation and authorization remain necessary.
QUESTION
Can a question-mark parameter represent a table name?
Click or press Enter to explain
ANSWER
No. Bound values are not arbitrary SQL identifiers or syntax; dynamic structure needs an application-controlled choice.
QUESTION
Where is a new ResultSet cursor initially?
Click or press Enter to explain
ANSWER
Before the first row. Call next and verify a row exists before reading values.
QUESTION
Why inspect affected-row counts for both updates?
Click or press Enter to explain
ANSWER
A zero or unexpected count does not satisfy this paired-transfer contract; do not silently treat it as success.
QUESTION
Can rollback undo an earlier auto-committed debit?
Click or press Enter to explain
ANSWER
No. That statement has already committed; rolling back later work does not restore it.
QUESTION
Does a commit exception always prove nothing persisted?
Click or press Enter to explain
ANSWER
No. Some failures can leave the outcome uncertain; a real operation needs verification and recovery rules.
20
❓MCQ Practice — Explain JDBC Decisions
PRACTICE
1. What implements database-specific JDBC communication?
PRACTICE
2. Where should database credentials be configured?
PRACTICE
3. What is the first JDBC parameter index?
PRACTICE
4. Which method returns a ResultSet for an appropriate query?
PRACTICE
5. What can executeUpdate return for no matching row?
PRACTICE
6. What must occur before reading a ResultSet row?
PRACTICE
7. How can a primitive getter distinguish SQL NULL afterward?
PRACTICE
8. Which mode groups the paired updates in this lab?
PRACTICE
9. What happens on a known credit failure in manual mode?
PRACTICE
10. What happens on the same failure in auto-commit mode?
PRACTICE
11. What is a question-mark placeholder appropriate for?
PRACTICE
12. Do model cleanup counters prove a real connection pool is healthy?
21
💻Extra Practice — Predict Persisted State
✅
Manual success
Reset, A → B, amount 3, manual/none. Expect A9/B7, 200 and committed outcome.
↩️
Manual rollback
Reset, A → B, 3, manual/credit error. Expect A12/B4, 500 and rolled-back outcome.
📉
Partial auto-commit
Reset, A → B, 3, auto/credit error. Expect A9/B4, 500 and partial debit.
🔢
Zero credit
Repeat with creditZero. Manual retains A12/B4; auto leaves A9/B4. Both reject the count.
➖
Insufficient source
Reset, B → A, amount 5. Expect 409, zero debit rows, no credit statement and unchanged tokens.
📨
Invalid input
Try 03, 3.0, spaces, 0, same source/destination or repeated amount shape. Expect 400, zero resources opened.
🔌
Unavailable fixture
Choose offline with valid input. Expect 503, unchanged balances and zero opened resources.
🧹
Repeated runs
Two successful A → B transfers of 3 produce A6/B10. Reset restores A12/B4, counters and outputs.
22
📌Quick Revision
🔌Driver: Database-specific JDBC implementation.
🧰DataSource: Configured connection factory.
🔑Prepared statement: Fixed SQL plus bound values.
📋ResultSet: Advance cursor before reading.
🔢Update count: Check the operation’s expected effect.
⚡Auto-commit: Separate statements can leave partial work.
🔄Transaction: Resolve paired work on one connection.
↩️Rollback: Handle known failures before commit.
🧹Ownership: Close the resources you own.
🧪Integration: Verify real database and driver behavior.
23
📖Glossary — Flip to Learn
TERM
JDBC
Click to see meaning
DEFINITION
JDBC
Java APIs for connecting to databases and executing database operations.
TERM
JDBC driver
Click to see meaning
DEFINITION
JDBC driver
An implementation that communicates with a particular database.
TERM
DataSource
Click to see meaning
DEFINITION
DataSource
A configured connection-factory abstraction.
TERM
Connection
Click to see meaning
DEFINITION
Connection
A database session used for statements and transaction control.
TERM
PreparedStatement
Click to see meaning
DEFINITION
PreparedStatement
A statement with fixed SQL structure and separately bound parameter values.
TERM
ResultSet
Click to see meaning
DEFINITION
ResultSet
A cursor-based result object returned by a query.
TERM
Affected-row count
Click to see meaning
DEFINITION
Affected-row count
A result indicating how many rows an update operation affected.
TERM
Auto-commit
Click to see meaning
DEFINITION
Auto-commit
A mode in which each completed statement commits its transaction.
TERM
Rollback
Click to see meaning
DEFINITION
Rollback
An attempt to undo uncommitted work in the current transaction.
TERM
Transaction isolation
Click to see meaning
DEFINITION
Transaction isolation
Rules governing visibility of concurrent database work.
24
🏆Final Challenge — Specify an Owned JDBC Operation
Design a backend operation that validates a source, destination and bounded integer amount, acquires an owned connection and executes two prepared updates.
Require the expected affected-row count for each before committing.
Keep identifiers and values separate from SQL structure.
Define the transaction boundary, rollback/error propagation and resource ownership.
Preserve the original failure if rollback or close also fails.
Explain why auto-commit cannot make two independent updates one atomic operation.
Test actual persisted state for success, zero debit, zero credit and a known execution failure.
Specify separate handling for uncertain commit outcomes and real concurrency.
A JSP renders accepted results; it does not own SQL or credentials.
Success criterion: trace the bindings, row counts, committed state and cleanup for every outcome.
Next: Level 26 — Databases and SQL for Web Applications.
25
✅Level 25 Complete?
Explain driver/API/data-source roles, prepared bindings, result cursors and update counts. Reproduce a committed transfer, known rollback and partial auto-commit outcome; identify the real database checks this lab cannot perform. Completion is a local study marker.