In the previous article, I wrote about what is Spring Data JPA and how to use it in the Spring Boot application. We also discussed the Spring Data JPA compelling features that make it a powerful tool.

In this article, you'll learn how to use Spring Data JPA with the H2 database in a Spring Boot project for storing, accessing, updating and deleting data (CRUD operations).

H2 is an open-source in-memory SQL database written in Java. It can be embedded in Java applications or use as a standalone database in client-server mode. An in-memory database is created when the application starts up and destroyed when the application shuts down.

Dependencies

We only need h2 and spring-data-starter-data-jpa dependencies to use H2 database with Spring Data JPA. For a Gradle project, add the following dependencies to your build.gradle file:

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'com.h2database:h2'

If you are using Maven, include the following dependencies to your pom.xml file:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
</dependency>

Alternatively, you can use Spring Initializr web tool to bootstrap a new Spring Boot application with the above dependencies.

Configure H2 Database

Spring Boot automatically configures the data source when it detects the H2 database dependency in the classpath. You do not need to do anything unless you want to customize the default configuration.

By default, Spring Boot configures the application to connect to an in-memory store with the username sa and an empty password. You can override these parameters by adding the following properties to your application.properties or application.yml file:

spring.datasource.url=jdbc:h2:mem:jpadb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=mypass
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

Since the in-memory database is removed when the application shuts down, we will lose the data when the application restarts.

To prevent this default behavior, we can switch to file-based storage by updating the spring.datasource.url property like below:

spring.datasource.url=jdbc:h2:file:/opt/jpadb

Check out the H2 documentation for more connections mode. For this example, we will use the in-memory mode.

Create an Entity

Let us create a simple entity class for storing Book objects:

Book.java

package com.attacomsian.jpa.domains;

import javax.persistence.*;

@Entity
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String title;
    @Column(unique = true)
    private String isbn;

    public Book() {
    }

    public Book(String title, String isbn) {
        this.title = title;
        this.isbn = isbn;
    }

    // getters and setters removed for brevity
}

The above Book class is very much similar to what we defined in the previous article. The class is annotated with @Entity which indicates that it is a JPA entity.

The id attribute is annotated with both @Id and @GeneratedValue annotations. This means that it is the object's auto-generated primary key.

The @Column annotation is used to specify the mapped column for a persistent property or field in the database. We set the unique property to true to indicate that this column is a unique key. In simple words, the isbn property must be unique for all books.

Create a Repository

Let us create a repository interface for our Book entity:

BookRepository.java

package com.attacomsian.jpa.repositories;

import com.attacomsian.jpa.domains.Book;
import org.springframework.data.repository.CrudRepository;

import java.util.List;

public interface BookRepository extends CrudRepository<Book, Long> {

    Book findByIsbn(String isbn);

    List<Book> findByTitleContaining(String title);
}

The BookRepository interface is very much self-explanatory. We are extending the Spring Data JPA CrudRepository interface to inherit several methods for manipulating Book entities.

We also defined two additional methods to get a Book entity by its ISBN value as well as all books that contain a specific keyword in their title value.

Create an Application Class

The next step is to create the main application class for our Spring Boot console application:

Application.java

package com.attacomsian.jpa;

import com.attacomsian.jpa.domains.Book;
import com.attacomsian.jpa.repositories.BookRepository;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class Application {

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

    @Bean
    public CommandLineRunner bookDemo(BookRepository bookRepository) {
        return (args) -> {

            // create books
            bookRepository.save(new Book("Thinking in Java", "0136597238"));
            bookRepository.save(new Book("Beginning Java 2", "1861002238"));
            bookRepository.save(new Book("Java Gently", "0201342979"));
            bookRepository.save(new Book("Java 2 Platform Unleashed", "0672316315"));

            // fetch all books
            System.out.println("Books found with findAll():");
            System.out.println("---------------------------");
            for (Book book : bookRepository.findAll()) {
                System.out.println(book.toString());
            }
            System.out.println();

            // fetch book by id
            Book book = bookRepository.findById(1L).get();
            System.out.println("Book found with findById(1L):");
            System.out.println("-----------------------------");
            System.out.println(book.toString());
            System.out.println();

            // fetch book by ISBN
            Book bookWithIBSN = bookRepository.findByIsbn("0201342979");
            System.out.println("Book found with findByEmail('0201342979'):");
            System.out.println("------------------------------------------");
            System.out.println(bookWithIBSN.toString());
            System.out.println();

            // fetch all books that contain keyword `java`
            System.out.println("Books that contain keyword 'java':");
            System.out.println("----------------------------------");
            for (Book b : bookRepository.findByTitleContaining("java")) {
                System.out.println(b.toString());
            }
            System.out.println();

            // update book title
            Book bookUpdate = bookRepository.findById(2L).get();
            bookUpdate.setTitle("Java Gently 2nd Edition");
            bookRepository.save(bookUpdate);
            System.out.println("Update book title:");
            System.out.println("------------------");
            System.out.println(bookUpdate.toString());
            System.out.println();

            // total books in DB
            System.out.println("Total books in DB:");
            System.out.println("------------------");
            System.out.println(bookRepository.count());
            System.out.println();

            // delete all books
            bookRepository.deleteAll();
        };
    }
}

The above main application class demonstrates how to use the BookRepository interface for creating, accessing, updating, and deleting Book entities.

Run the Application

You can easily run the application from the command line by using Gradle or Maven build tools. For Gradle, run the application by executing the following command:

$ ./gradlew bootRun

For Maven, you can run the application by typing:

$ ./mvnw spring-boot:run

Once the application is started, you should see the following output printed on the console:

Books found with findAll():
---------------------------
Book{id=1, title='Thinking in Java', isbn='0136597238'}
Book{id=2, title='Beginning Java 2', isbn='1861002238'}
Book{id=3, title='Java Gently', isbn='0201342979'}
Book{id=4, title='Java 2 Platform Unleashed', isbn='0672316315'}

Book found with findById(1L):
-----------------------------
Book{id=1, title='Thinking in Java', isbn='0136597238'}

Book found with findByEmail('0201342979'):
------------------------------------------
Book{id=3, title='Java Gently', isbn='0201342979'}

Books that contain keyword 'java':
----------------------------------

Update book title:
------------------
Book{id=2, title='Java Gently 2nd Edition', isbn='1861002238'}

Total books in DB:
------------------
4

Source code: Download the complete source code from GitHub available under MIT license.

Conclusion

That's all folks for today. In this article, you have learned how to use Spring Data JPA with H2 in-memory database for storing and retrieving books in a Spring Boot application.

Check out the getting started with Spring Data JPA guide to learn more about its core features and how to configure different data sources.

If you are using MySQL with Spring Data JPA, check out Accessing Data with Spring Data JPA and MySQL guide.

✌️ Like this article? Follow @attacomsian on Twitter. You can also follow me on LinkedIn and DEV. Buy me a coffee (cost $3)

Need help to start a new Spring Boot or MEAN stack project? I am available for contract work. Hire me to accomplish your business goals with engineering and design. Let’s talk about your project: hi@attacomsian.com.