How to build a CRUD REST API using Spring Boot 2, JPA/Hibernate and MySQL

How to build a CRUD REST API using Spring Boot 2, JPA/Hibernate and MySQL

In this article we will learn how to develop a CRUD RESTFul API with Spring Boot 2 + JPA/Hibernate and MySQL as database.

In this article we will learn how to develop a CRUD RESTFul API with Spring Boot 2 + JPA/Hibernate and MySQL as database.

The end goal of these articles is to deploy this application on Oracle Cloud. But first, we will develop and test the application using a local database.

Before we get started, here is a list of what we need to complete this tutorial:

The API we will develop

We will create a Contact Resource exposing three services using RESTFul URIs and HTTP methods:

  • Retrieve all contacts - @GetMapping(“/contacts)
  • Get details of specific contact - @GetMapping(“/contacts/{id}”)
  • Delete a contact - @DeleteMapping(“/contacts/{id}”)
  • Create a new contact - @PostMapping(“/contacts)
  • Update existing contact details - @PutMapping(“/contacts/{id}”)

Creating the REST Spring Boot application

To create the Spring Boot application, we’ll use, which will provide us some bootstrap code (main class and pom.xml files). We need the WebJPALombok and MySQL packages for this example:

Look at the From the above diagram, we have specified the following details:

Generate: Maven Project
Java Version: 1.8 (Default)
Spring Boot:2.1.1
Group: com.loiane
Artifact: spring-cloud-mysql
Dependencies: Web, JPA, Lombok, MySQL

After entering all details, click on Generate Project button, download the zip file, extract its contents to your workspace and open it in your favorite IDE.

Project Structure

The following screenshot shows the structure of the project we will create.

Creating the model (JPA Entity)

The first class we will create is the JPA Entity. We will create a class Contact with a primary key id:

The model is the same as part 1 of this article series, but we will specify the how the ID will be auto generated because we are no longer using H2 database.
public class Contact {

@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;

private String name; private String email; private String phone; }

The following annotations are from project Lombok and help us keep our classes (specially model/POJO) cleaner without the getters and setters:

  • AllArgsConstructor: automatically creates a class construtor with all arguments (properties).
  • NoArgsConstructor: automatically creates an empty class construtor with all arguments (properties).
  • Data: creates toStringequalshashCodegetters and setters.

Creating the JPA Repository

To easily access the methods to manipulate the Contact table, we just need to create an interface that extends JpaRepository passing the class that represents our model and the type of the primary key as generic arguments:

public interface ContactRepository 
    extends JpaRepository<Contact, Long> { }

The JpaRepository interface provides a simple and easy way to access all the CRUD operations.

Creating the Controller

To access our data, we will also need a Controller.

public class ContactController {

private ContactRepository repository;

ContactController(ContactRepository contactRepository) { this.repository = contactRepository; }

// CRUD methods here }

The @RestController annotation contains the @Controller and @ResponseBody annotations. The @Controller annotation represents a class with endpoints and the @ResponseBody indicates indicates a method return value should be bound to the web response body (according to the documentation).

The @RequestMapping("/contacts") indicates that the url of the API in this controller will start with /contacts, so we will be able to access http://localhost:8080/contacts as our endpoint.

Please note we are not using the @Autowired annotation to automatically inject the repository. We are using dependency injection through the constructor as it is a recommended best practice.

As this is a simple example, we are not creating a Service class to iterate with the repository. Creating a service layer is a good practice as we can keep our controller class clean and add any required business logic to the service instead.

Let’s take a look at each method next.

Retrieve All Contacts (GET /contacts)
public List findAll(){
  return repository.findAll();

The findAll method is going to retrieve all the records from the database (select * from contact).

As this is a RESTful API, we can omit the @RequestMapping(value="/contacts", method=RequestMethod.GET) and simply use @GetMapping.

Retrieve a Contact by ID (GET /contacts/{id})
@GetMapping(path = {"/{id}"})
public ResponseEntity<Contact> findById(@PathVariable long id){
  return repository.findById(id)
          .map(record -> ResponseEntity.ok().body(record))

The @PathVariable annotation binds the method parameter id with the path variable {id}.

we will go to the database and will try to retrieve the contact (select * from contact where id = ?). If a contact is found, we return it (HTTP 200 - OK), else, we return HTTP 404 -Not Found.

Create a new Contact (POST /contacts)
public Contact create(@RequestBody Contact contact){

The @RequestBody annotation indicates a method parameter should be bound to the body of the web request. This means the method expects the following content from que request (in JSON format):

    "name": "Java",
    "email": "[email protected]",
    "phone": "(111) 111-1111"

Spring will automatically parse the request and create a variable of type Contact with its contents. Then, it will save it. The id of the contact will be null, therefore the save method will perform an insert into the Contact table.

Update a Contact (PUT /contacts)
  public ResponseEntity<Contact> update(@PathVariable("id") long id,
                                        @RequestBody Contact contact){
    return repository.findById(id)
        .map(record -> {
            Contact updated =;
            return ResponseEntity.ok().body(updated);

In order to update a contact, we need to inform its ID in the path variable. We also need to pass the updated contact.

Next, we will try to find the contact to be updated. If the contact is found, we update the values from the record from the database with the values passed as parameter to the method and save it. In this case, as the record exists, an update statement will performed in the contact table. We also return the updated contact. In case the contact is not found, it returns HTTP 404.

Remove a Contact (DELETE /contacts/{id})
@DeleteMapping(path ={"/{id}"})
  public ResponseEntity<?> delete(@PathVariable("id") long id) {
    return repository.findById(id)
        .map(record -> {
            return ResponseEntity.ok().build();

To remove a contact, we first need to retrieve it from the database. In case it is found, we delete it passing its ID and return HTTP 200 to indicate the deletion was performed successfully. In case the contact is not found, we return HTTP 404.

Initializing the MySQL database

As a last step, we are going to insert a few records in the MySQL contact table by declaring a Bean that returns a CommandLineRunner - this step is optional in case you already using an existing database/table.

public class SpringCloudMysqlApplication {

public static void main(String[] args) {, args);

CommandLineRunner init(ContactRepository repository) {
    return args -&gt; {
        LongStream.range(1, 11)
                .mapToObj(i -&gt; {
                    Contact c = new Contact();
                    c.setName("Contact " + i);
                    c.setEmail("contact" + i + "");
                    c.setPhone("(111) 111-1111");
                    return c;
                .map(v -&gt;


Configuring MySQL Database

In order for our code to be able to connect to a MySQL database, we also need to inform the connection details. We are going to add these details inside src/maind/resources/

## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)

The SQL dialect makes Hibernate generate better SQL for the chosen database

In case you want Hibernate to automatically generate the table in the database, we can use the following configuration as well:

# Hibernate ddl auto (create, create-drop, validate, update)

Although this makes easier during the development, this is not recommended in production. For production, you might want to create a functional ID (user/password) that can perform all CRUD operations in the tables (DML (Data Manipulation Language) commands), but cannot perform any DDL (Data Definition Language) commands (Create, Drop, Alter tables, and so on).

To create the contact table, we can use the following SQL script:

  name VARCHAR(255) NULL,
  email VARCHAR(255) NULL,
  phone VARCHAR(45) NULL,
  PRIMARY KEY (id));


Testing the APIs

We can test the API using Postman. If you use Visual Studio Code, you can also use the REST Client extension.

File for testing using the REST Client extension is also included in the source code


In this article, we developed and tested a CRUD API connecting to a real database locally. 

I hope this tutorial will surely help and you if you liked this tutorial, please consider sharing it with others

spring-boot java hibernate mysql web-development

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

Productive Web Development in Java with IntelliJ IDEA, Spring Boot and Vaadin

We cover tips and tricks to help you become a more productive web app developer. We build a small web app using Vaadin's Java API and Spring Boot. We show you how to set up IntelliJ IDEA to automatically reload your app and browser as you develop and cover our favorite shortcuts and hacks for productive and enjoyable web app development in Java.

Hire Web Developer

Looking for an attractive & user-friendly web developer?, a leading web, and mobile app development company, offers web developers for hire through flexible engagement models. You can **[Hire Web...

Top 10 Advanced Java and Spring Boot Courses for Full-Stack Java Developers

These are best online courses to learn Spring Boot, Advanced Java, Docker, React, Microservices, DEvops, and Angular to become full stack Java developer.

Best MySQL DigitalOcean Performance – ScaleGrid vs. DigitalOcean Managed Databases

Compare ScaleGrid MySQL vs. DigitalOcean Managed Databases - See which offers the best MySQL throughput, latency, and pricing on DigitalOcean across workloads.

Building a Simple CRUD App using Spring Boot, MySQL, JPA/Hibernate

In this article, we will walk through how to build a simple CRUD application using Spring Boot, MySQL, JPA/Hibernate and Okta OpenID Connect (OIDC) Single Sign-On (SSO).