Spring JDBC Basics
Understand why Spring JDBC exists and how it eliminates the repetitive boilerplate of raw JDBC code.
Introduction
Java's built-in JDBC API can talk to any relational database, but using it directly means writing the same connection-opening, statement-closing, exception-translating code over and over. Spring JDBC wraps raw JDBC in a much thinner, safer layer. Before diving into JdbcTemplate in the next lesson, this lesson explains exactly what problem Spring JDBC solves and why it is worth using even in an era of full ORMs.
- What raw JDBC requires you to manage manually.
- What Spring JDBC removes from that picture.
- How a DataSource bean fits into the Spring container.
- How Spring translates checked SQLExceptions into unchecked exceptions.
The Pain of Raw JDBC
A simple "select one row" query with raw JDBC requires opening a Connection, creating a PreparedStatement, executing it, iterating a ResultSet, and closing all three resources - even when nothing goes wrong. When something does go wrong, you also need a try/finally (or try-with-resources) to make sure everything closes anyway.
public Book findById(long id) throws SQLException { String sql = "SELECT id, title, author FROM books WHERE id = ?"; try (Connection conn = dataSource.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setLong(1, id); try (ResultSet rs = ps.executeQuery()) { if (rs.next()) { return new Book(rs.getLong("id"), rs.getString("title"), rs.getString("author")); } } } return null;}That is roughly a dozen lines of resource management and exception plumbing to run a single SELECT - and every checked SQLException forces callers up the chain to declare throws SQLException or catch it, whether or not they can meaningfully react to it.
What Spring JDBC Provides
Spring JDBC (centered on the JdbcTemplate class you will use in the next lesson) takes over the repetitive parts: opening and closing connections and statements, iterating result sets, and translating low-level database errors into a consistent set of Spring exceptions. You are left writing only the SQL and the logic for turning a row into a Java object.
| Raw JDBC | Spring JDBC |
|---|---|
| Manually open/close Connection | Handled automatically by JdbcTemplate |
| Manually open/close PreparedStatement | Handled automatically by JdbcTemplate |
| Manually iterate ResultSet | Row mapping handled by a RowMapper callback |
| Checked SQLException everywhere | Unchecked DataAccessException hierarchy |
The DataSource Bean
Both raw JDBC and Spring JDBC rely on a DataSource - an object that knows how to produce database connections, typically backed by a connection pool. In a Spring application, the DataSource is configured once as a bean and then injected wherever it is needed, including into JdbcTemplate.
@Configurationpublic class DataSourceConfig {
@Bean public DataSource dataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost:3306/bookstore"); dataSource.setUsername("app_user"); dataSource.setPassword("secret"); return dataSource; }}DriverManagerDataSource is fine for learning, but it opens a new physical connection every time. Production applications use a pooling DataSource such as HikariCP, which Spring Boot configures automatically when it is on the classpath.
Consistent Exception Handling
Raw JDBC throws a single checked SQLException for almost everything - a duplicate key, a lost connection, a syntax error - forcing you to parse error codes to tell them apart. Spring JDBC translates the underlying vendor-specific error into a specific, unchecked subclass of DataAccessException, so calling code can catch exactly the failure it cares about.
try { jdbcTemplate.update("INSERT INTO books (id, title) VALUES (?, ?)", id, title);} catch (DuplicateKeyException ex) { // a book with this id already exists} catch (DataAccessException ex) { // any other data access problem}Common Mistakes
- Still manually opening and closing Connections after adopting Spring JDBC, defeating its purpose.
- Using DriverManagerDataSource in production instead of a pooled DataSource.
- Catching the generic DataAccessException everywhere instead of its more specific subclasses when a specific reaction is needed.
- Concatenating user input directly into SQL strings instead of using parameterized queries (covered further in the next lesson).
- Assuming Spring JDBC is an ORM - it is a thin layer over JDBC, not an object-relational mapper like JPA/Hibernate.
Best Practices
- Configure exactly one DataSource bean and let Spring inject it wherever it is needed.
- Use a connection pool (HikariCP is the Spring Boot default) in any real deployment.
- Let JdbcTemplate manage resource lifecycle instead of touching Connection or PreparedStatement directly.
- Catch specific DataAccessException subclasses when your code needs to react differently to different failures.
- Reach for Spring JDBC when you want SQL control without an ORM, and JPA/Hibernate when you want full object mapping.
Frequently Asked Questions
No. Spring JDBC is a thin convenience layer directly over JDBC and SQL. JPA/Hibernate is a full ORM that maps entire object graphs to tables and can generate SQL for you.
Yes - that is the point. You keep full control of your SQL; Spring JDBC just removes the resource management and exception boilerplate around running it.
Because most callers cannot meaningfully recover from a low-level database failure at every call site, forcing every method up the stack to declare or catch SQLException adds ceremony without adding safety.
Key Takeaways
- Raw JDBC requires manually managing Connections, Statements, and ResultSets for every query.
- Spring JDBC removes that boilerplate while leaving you in full control of the SQL itself.
- A DataSource bean, ideally backed by a connection pool, is the shared entry point to the database.
- Spring translates vendor-specific SQLExceptions into a consistent, unchecked DataAccessException hierarchy.
Summary
Spring JDBC exists to strip away repetitive resource management while keeping SQL fully in your hands. Now that you understand why it exists, the next lesson puts it to work with JdbcTemplate - the class you will actually call to run queries and updates.