Home Blog Projects

Spring Data Access - JDBC, Boot, and Spring Data

· 6min

In my Spring basics series, I described how Spring is an open-source Java application framework. For the persistence layer of an application, we can use many approaches in Spring. In this post we will go over JDBC, Spring Data, and data access as a whole in Spring applications.

Developers can choose different modules for the data access layer depending on the repository type. In this series we’ll develop a telecom application for adding, updating, and deleting customer and their call plans.

Demos:


JDBC

We’ll take a look on how we’d add and remove customers with JDBC. We’d need to create a table in a SQL database like the following:

create database jdbc;

use jdbc;

create table customer(
phone_no bigint primary key,
name varchar(50),
age integer,
gender char(10),
address varchar(50),
plan_id integer
);

After, we’d have to define domain classes to represent customer details. We’d also need appropriate dependencies in the pom.xml for connecting to the database. For now, we’ll mock the presentation layer by sending requests to our service layer from the main() method of our application.

We’d set up the data access layer with an interface CustomerDAO and a repository class CustomerDAOImpl to implement the interface.

package com.maxdemaio.repository;

import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;

import com.maxdemaio.entity.Customer;

public class CustomerDAOImpl implements CustomerDAO {
    Connection con = null;
    PreparedStatement stmt = null;
    ResultSet rs = null;

    @Override
    public void insert(Customer customer) {
        try (FileInputStream fis = new FileInputStream("src/main/resources/application.properties");) {
            Properties p = new Properties();
            p.load(fis);
            String dname = (String) p.get("jdbc.driverClassName");
            String url = (String) p.get("spring.datasource.url");
            String username = (String) p.get("spring.datasource.username");
            String password = (String) p.get("spring.datasource.password");
            Class.forName(dname);
            // Register driver
            con = DriverManager.getConnection(url, username, password);
            // Create connection
            String query = "insert into customer values (?,?,?,?,?,?)";
            // Create prepared statement
            stmt = con.prepareStatement(query);
            stmt.setLong(1, customer.getPhoneNumber());
            stmt.setString(2, customer.getName());
            stmt.setInt(3, customer.getAge());
            stmt.setString(4, customer.getGender().toString());
            stmt.setString(5, customer.getAddress());
            stmt.setInt(6, customer.getPlanId());
            // Execute query
            stmt.executeUpdate();
            System.out.println("Record inserted");
        } catch (Exception e) {
            System.out.println("error: " + e.getMessage());
        } finally {
            try {
                // Close the prepared statement
                stmt.close();
                // Close the connection
                con.close();
            } catch (Exception e) {
                System.out.println("error: " + e.getMessage());
            }
        }
    }

    @Override
    public int remove(Long phoneNo) {
        int result = 1;
        try (FileInputStream fis = new FileInputStream("src/main/resources/application.properties");) {
            Properties p = new Properties();
            p.load(fis);
            String dname = (String) p.get("jdbc.driverClassName");
            String url = (String) p.get("spring.datasource.url");
            String username = (String) p.get("spring.datasource.username");
            String password = (String) p.get("spring.datasource.password");
            Class.forName(dname);
            // Create connection
            con = DriverManager.getConnection(url, username, password);
            String query = "DELETE FROM Customer WHERE phone_no = ?";
            // Create prepared statement
            stmt = con.prepareStatement(query);
            stmt.setLong(1, phoneNo);
            // Execute query
            result = stmt.executeUpdate();
        } catch (Exception e) {
            System.out.println("error: " + e.getMessage());
        } finally {
            try {
                // Close the prepared statement
                stmt.close();
                // Close the connection
                con.close();
            } catch (Exception e) {
                System.out.println("error: " + e.getMessage());
            }
        }
        return result;
    }
}

For JDBC, we can also use the JdbcTemplate class to concentrate on SQL queries and their parameters. As noted in the example above, you need to configure it with a DataSource. Spring-JDBC also has a JdbcDaoSupport class that you can extend to develop your DAO.

Setting this up is tedious. We have to write the code to perform common database CRUD operations. Spring Data helps us overcome these limitations by abstracting this away. We can also add on top of the built-in functions.

Spring Data

Spring Data is a high-level project that searches to unify data access with SQL and NoSQL data stores. There are also sub projects for technologies like MongoDB, Redis, Neo4j and more. It simplifies the data access layer by removing the implementations as shown above from your application. The only artifact that needed is the interface.

Spring Data Image

Spring Boot

Using only Spring for application development can be challenging. Spring Boot is a solution that has come to market by the Spring team.

Nobody likes the overhead of configuration. Spring Boot is a framework built on top of Spring that helps build Spring applications with ease. The goal is to avoid boilerplate configuration and allow for quickness. Spring Boot is opinionated. For example, it uses an embedded Tomcat as the default web container. It is also customizable. If you want to use log4j instead of Spring Boot built-in logging support you can make changes in your pom.xml file.

The main Spring Boot features are:

@SpringBootApplication
public class ClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(ClientApplication.class, args);
    }
}

@SpringBootApplication indicates that is a configuration class and triggers auto-configuration and component scanning. It is a combination of the following annotations and their default settings:

To create a Spring Boot application, we can use the following tools (I’ll be using Spring Initializr throughout the series):

Spring Initializr Image

Overall Data Access

When creating a data access layer we should always annotate data access objects (DAOs) with the @Repository annotation. This is important because it links exceptions from their underlying technologies (Hibernate, JDBC, JPA, etc.) to the proper DataAccessException subclass.

Thanks to the DataAccessException subclass, you can swap out an underlying technology and keep your try/catch statements the same. But you should usually not catch these exceptions. You shouldn’t is because the underlying technology could have rolled back the transaction in question. Thus, you wouldn’t want to continue execution in an alternate path if this happened. It’s still important to annotate your DAOs with @Repository because the bean will be auto-added by the auto-scan.

Spring also provides an API for transaction management that goes well with data access. There is a matching transaction manager for local transactions or JTA for distributed transactions.

Resources