Building My First Microservice - Part 3 (Spring Data JPA)

Welcome back to my ongoing "Building Your First Microservice" series! In the last two articles, we learned how to create a simple Spring Boot microservice and add monitoring with Spring Boot Actuator.


In this article, we will learn how to connect our microservice to a database using the Java Persistence API (JPA). JPA provides an object-relational mapping (ORM) to simplify interacting with a relational database from Java code.




Why Use JPA?

JPA offers several benefits:

  • Allows defining plain old Java objects (POJOs) that map to database tables, known as "entities"
  • Automatically converts data between Java objects and database rows through ORM
  • Provides simple APIs for CRUD operations without writing SQL queries
  • Handles complex features like caching, transactions, inheritance mapping and more

For this tutorial, you will need:

This removes a lot of boilerplate JDBC and SQL code and keeps our microservice code clean.


- A Spring Boot project set up. Refer to the first two articles on getting started with Spring Boot and adding Actuator.

 uth

- A MySQL database installed and running with a sample "user" table created.


Adding Dependencies

Add the 'spring-boot-starter-data-jpa' dependency to your 'pom.xml':



<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>


This will transitively pull in all required dependencies like Hibernate, Spring Data JPA, and the JPA API itself.


Also add the MySQL connector:



<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>


Configuring Data Source

In 'application.yaml', specify your MySQL URL, credentials, etc:



spring:
datasource:
url: jdbc:mysql://localhost:3306/test
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver


This configures the data source that will be injected into your repository interfaces.


Configuring Hibernate

Spring Boot auto-configures Hibernate as the JPA implementation based on the "spring-boot-starter-data-jpa"dependency.


We can further configure Hibernate by adding properties in 'application.yaml':



jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL5InnoDBDialect

  • 'ddl-auto = update' - Automatically creates database schemas based on entities
  • 'show-sql = true' - Logs the generated SQL queries
  • 'dialect' - Specifies the dialect for the MySQL database

With this, Hibernate will automatically manage and update our database schema as we modify entities.It will also show the SQL logs so we can peek into the queries being executed.The dialect optimises SQL generation for the particular database, MySQL in our case.

Creating the Entity

Annotate your model class with '@Entity' and specify the table name if different from class name:



@Entity
@Table(name = "user_info")
public class User {
@Id
private int id;
private String firstname;
private String lastname;
private String email;
//getters, setters and constructors


Creating the Repository


Create a repository interface extending `JpaRepository` and specify the entity type: 



public interface UserRepository extends JpaRepository<User, String> {

}


That's it! No need to implement CRUD methods.


Inject this repository into your service class and start using it:


@Service
public class UserServiceImpl implements UserService {

UserRepository userRepository; //Injection of the repository

public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}

@Override
public String createUser(User user) {
userRepository.save(user);
return "success";
}

@Override
public String updateUser(User user) {
userRepository.save(user);
return "success";
}

@Override
public String deleteUser(int id) {
userRepository.deleteById(String.valueOf(id));
return "success";
}

@Override
public User getUser(int id) {
return userRepository.findById(String.valueOf(id)).get();
}

@Override
public List<User> getAllUsers() {
return userRepository.findAll();
}
}


Controller


UserApiController class can be implemented like this:


@RestController
@RequestMapping("/user")
public class UserAPIController {
public UserAPIController(UserService userService) {
this.userService = userService;
}

UserService userService;


@GetMapping("{id}")
public User getUser(@PathVariable("id") int id){
return userService.getUser(id);
}
@GetMapping
public List<User> getAllUser(){
return userService.getAllUsers();
}

@PostMapping
public String createUser(@RequestBody User user){
userService.createUser(user);
return "User created successfully";
}

@PutMapping
public String updateUser(@RequestBody User user){
userService.updateUser(user);
return "User updated successfully";
}

@DeleteMapping("{id}")
public String deleteUser(@PathVariable int id){
userService.deleteUser(id);
return "User deleted successfully";
}


}

Overview of the project structure




Testing it Out


Call the 'POST /user' endpoint with a sample student JSON payload:




This will save the student to the database without writing any JDBC code!

Similarly we can call :

  • 'GET/user/id'
  • 'UPDATE/user/id'
  • 'DELETE/user/id'

View the code

The full code for this project is available on GitHub:


https://github.com/vlbandara/userAPI


And that's it! We learned how to integrate a database into our Spring Boot microservice using JPA and Spring Data repositories. Stay tuned for more articles in this series.

Post a Comment

Previous Post Next Post