DEV Community

Cover image for Connecting Spring Boot Applications to a Database with Spring Data JPA
Igor Venturelli
Igor Venturelli

Posted on • Originally published at igventurelli.io

Connecting Spring Boot Applications to a Database with Spring Data JPA

Simplify Spring Boot database integration with Spring Data JPA

In modern software development, databases form the backbone of most applications, holding crucial data that powers the business logic. Spring Data JPA is a part of the larger Spring ecosystem that simplifies data access through powerful abstractions over JPA (Java Persistence API). In this post, we will dive into how to connect Spring Boot applications to a PostgreSQL database using Spring Data JPA, explore key annotations, understand repository interfaces, and provide practical code examples to solidify the concepts.

Spring Data JPA Starter

The first step to leveraging Spring Data JPA in a Spring Boot application is to include the Spring Data JPA starter dependency in your project. This starter provides all necessary dependencies to integrate JPA with your application.

In your pom.xml (for Maven users), include the following:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
Enter fullscreen mode Exit fullscreen mode

For Gradle users, add the following to your build.gradle:

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
Enter fullscreen mode Exit fullscreen mode

This dependency brings together Spring Data JPA, Hibernate (as the default JPA provider), and other necessary libraries.

Connecting to PostgreSQL

To connect a Spring Boot application to a PostgreSQL database, you’ll need to configure a few properties in application.properties (or application.yml).

Here are the key properties:

spring.datasource.url=jdbc:postgresql://localhost:5432/your_database
spring.datasource.username=your_username
spring.datasource.password=your_password

# do not use the following property value in production
spring.jpa.hibernate.ddl-auto=update
Enter fullscreen mode Exit fullscreen mode
  • spring.datasource.url: This is the JDBC URL for your PostgreSQL database. The format is jdbc:postgresql://[host]:[port]/[database].
  • spring.datasource.username: The database username.
  • spring.datasource.password: The database password.
  • spring.jpa.hibernate.ddl-auto: Defines how Hibernate will handle schema management. Set to update to automatically update the database schema.

Environment Variables for Database Configuration

In production environments, hardcoding database credentials in your configuration files is not recommended. Instead, you can pass these properties as environment variables.

As usual for the most Spring Starters (or probably all of them) you can pass the same attributes through environment variables just by using capital letters and replacing the dots by underscores, like the example below:

# application.properties version
spring.datasource.url=jdbc:postgresql://localhost:5432/your_database
spring.datasource.username=your_username
spring.datasource.password=your_password

# environment variables version
export SPRING_DATASOURCE_URL=JDBC:POSTGRESQL://LOCALHOST:5432/YOUR_DATABASE
export SPRING_DATASOURCE_USERNAME=YOUR_USERNAME
export SPRING_DATASOURCE_PASSWORD=YOUR_PASSWORD
Enter fullscreen mode Exit fullscreen mode

Key JPA Annotations

When working with JPA, you'll encounter a variety of annotations that map Java objects to database tables. Here are some of the most commonly used:

  • @Entity: Marks a class as a JPA entity, meaning it will be mapped to a database table.

    @Entity
    public class User {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        @Column(nullable = false)
        private String name;
    
        // Getters and setters
    }
    
  • @Table (optional): If you want to specify the table name or schema in the database, you can use this annotation.

    @Entity
    @Table(name = "users")
    public class User {
        // Fields and annotations
    }
    
  • @Id: Specifies the primary key of the entity.

  • @GeneratedValue: Indicates how the primary key should be generated (e.g., using an auto-incrementing sequence).

  • @Column: Used to define additional attributes of the column in the database, such as nullable, length, and unique.

Repositories as Interfaces

In Spring Data JPA, repositories are simply interfaces that allow you to perform CRUD operations without writing boilerplate code. Spring Data JPA provides several repository interfaces that we can extend to gain basic functionality, as well as custom queries.

Two Main Repository Interfaces

  1. CrudRepository: This is the most basic repository interface and provides CRUD operations for entity management.

    • Pros: Light and sufficient for simple CRUD operations.
    • Cons: Limited functionality compared to JpaRepository.
    public interface UserRepository extends CrudRepository<User, Long> {}
    
  2. JpaRepository: Extends CrudRepository and provides additional features like pagination and batch updates.

    • Pros: More powerful and flexible than CrudRepository.
    • Cons: Slightly heavier due to added functionality.
    public interface UserRepository extends JpaRepository<User, Long> {}
    

@Repository Annotation

The @Repository annotation in Spring Data is used to indicate that the class provides the mechanism for CRUD operations on a particular entity. Spring handles all the actual implementation behind the scenes, and you rarely have to write boilerplate code yourself.

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByName(String name);
}
Enter fullscreen mode Exit fullscreen mode

With this method name (findByName) Spring will understand that it needs to query the database on the table specified by the User entity, searching for a user with the name column equals to the name passed on the method's argument. You don't need to it on your own.

💡

Heads Up! This is example shows a query by name and expects none or a single value, which on the real world would break as we can have multiple users on our database with same name. This is example is to illustrate the behavior of the method's name.

Code Example: Putting It All Together

Let's build a simple user service that connects to a PostgreSQL database using Spring Data JPA.

1. Entity Class:

@Entity
public class User {

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

    @Column(nullable = false)
    private String name;

    @Column(nullable = false)
    private String email;

    // Constructors, Getters, and Setters
}
Enter fullscreen mode Exit fullscreen mode

2. Repository Interface:

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByEmail(String email);
}
Enter fullscreen mode Exit fullscreen mode

3. Service Layer:

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public User createUser(User user) {
        return userRepository.save(user);
    }

    public Optional<User> getUserByEmail(String email) {
        return userRepository.findByEmail(email);
    }

    public List<User> getAllUsers() {
        return userRepository.findAll();
    }
}
Enter fullscreen mode Exit fullscreen mode

4. Controller Layer:

@RestController
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private UserService userService;

    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        return new ResponseEntity<>(userService.createUser(user), HttpStatus.CREATED);
    }

    @GetMapping("/{email}")
    public ResponseEntity<User> getUserByEmail(@PathVariable String email) {
        return userService.getUserByEmail(email)
                          .map(user -> new ResponseEntity<>(user, HttpStatus.OK))
                          .orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
    }
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

Spring Data JPA streamlines the process of interacting with databases in Spring Boot applications, making it both intuitive and powerful. With the addition of PostgreSQL, configuring the datasource properties either directly in the configuration file or through environment variables ensures flexibility and security, especially in production environments. By leveraging the starter dependency, key annotations like @Entity, and repository interfaces like JpaRepository and CrudRepository, you can quickly set up your data layer without having to deal with low-level SQL.


Let’s connect!

📧 Don't Miss a Post! Subscribe to my Newsletter!
➡️ LinkedIn
🚩 Original Post
☕ Buy me a Coffee

Top comments (2)

Collapse
 
programmerraja profile image
Boopathi

This is a great overview of connecting Spring Boot applications to a database with Spring Data JPA. I particularly appreciate the clear explanation of repository interfaces and how to use custom queries. Thanks for sharing!

Collapse
 
igventurelli profile image
Igor Venturelli

Oh! Thanks buddy! Happy to read this message! I am glad it helped somehow!