Friday, July 24, 2020

Microservice Part 2 - Spring Boot + database integration

Hello Friends, 
I am back with another blog in this series of "microservices".


Introduction - 

In my first blog, we learned and developed basic microservice where we persist data in memory with the help of Array List data structure. In this part of the blog, we will go one step ahead and learn database connectivity for our microservice. Database is important part of application and connectivity with database is must for most of the applications.  

We have covered basic development setup in previous post. Learners who have not gone through first part then please go through that to complete the setup. That part will also help to develop basic understanding of microservices. We have listed all the necessary URLs or websites to download tools like eclipse, maven.  

Here we go...

Prerequisite -


Installation & Setup -


Please Refer Part 1. (Installation & Setup section)


There are multiple ways to connect with database in spring boot framework. it supports Jpa, jdbctemplate, basic datasource connectivity. Spring boot also provides flexibility to connect with multiple database simultaneously.

We will use Spring Boot JPA driver connection to connect the database.


Implementation - 


Step 1 - Download Part 1 project code from git repository (~ already have code then move to step 3)
 

Step 2 - Import project in eclipse.

Step 3 - Run below command to check everything is good and there is no error in project.
mvn clean package   

Step 4 - To add support for database, add below dependency in pom.xml. To keep it easy, we will use h2 runtime memory database. 

<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>


Step 5 - Create application.properties file under java/resource folder. Copy below content.

spring.jpa.properties.hibernate.format_sql=true
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update

spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb

  

Run the application and ensure there is no error.


Once application is up, you can access application as well as memory H2 database.


DB Interface - http://localhost:8080/h2-console/

Application  - http://localhost:8080/todos


Let's start the code changes connect database.


Step 1 - Create an JPA Repository interface. we just need to extend JPARepository. It will provide useful method automatically. we don't need to add basic method to perform CRUD operation in DB.

package com.sarvesh.microservice.firstmicroservice.repository;

import com.sarvesh.microservice.firstmicroservice.data.ToDoDataObject;
import org.springframework.data.jpa.repository.JpaRepository;


public interface ToDoRepository extends JpaRepository<ToDoDataObject, Long> {}

Step 2 - Till now, we have added new required code and configuration for database. In this step, we will do changes in existing service and data entity classes.

Step 2.1 - Changes in ToDoDataObject data object . Minor three annotation added to map with table.

package com.sarvesh.microservice.firstmicroservice.data;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import java.util.Date;

@Entity(name = "todo")
// Change 1
public class ToDoDataObject {

@Id // Change 2
@GeneratedValue // Change 3
private Long id;
private String task;
private Date targetDate;

public ToDoDataObject() {
super();
}

public ToDoDataObject(Long id, String task, Date targetDate, boolean done) {
super();
this.id = id;
this.task = task;
this.targetDate = targetDate;
this.done = done;
}
private boolean done;

public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTask() {
return task;
}
public void setTask(String task) {
this.task = task;
}
public Date getTargetDate() {
return targetDate;
}
public void setTargetDate(Date targetDate) {
this.targetDate = targetDate;
}
public boolean isDone() {
return done;
}
public void setDone(boolean done) {
this.done = done;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (id ^ (id >>> 32));
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ToDoDataObject other = (ToDoDataObject) obj;
if (id != other.id)
return false;
return true;
}



}

 
Step 2.2 -  Changes in service class. we are using newly created ToDoRepository
class to perform database operation. You can see we have not defined those functions in repository but spring boot framework added it for you. 
package com.sarvesh.microservice.firstmicroservice.services;

import java.util.List;

import com.sarvesh.microservice.firstmicroservice.repository.ToDoRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.sarvesh.microservice.firstmicroservice.data.ToDoDataObject;

@Service
public class ToDoAppService {

@Autowired
private ToDoRepository toDoRepository;

public List<ToDoDataObject> getAllToDos() {
return toDoRepository.findAll();
}

public ToDoDataObject save(ToDoDataObject dataObject) {
if (null == dataObject.getId()) {
toDoRepository.save(dataObject);
} else {
deleteToDo(dataObject.getId());
}

return dataObject;

}

public ToDoDataObject deleteToDo(long id) {

return toDoRepository.findById(id).get();

}

public ToDoDataObject findByUId(long id) {

return toDoRepository.findById(id).get();
}

} 

Step 2.3 -  Changes in Controller 

*****No change in controller class because we designed our microservice in such a way that we can change database layer without impacting our controller layer. it means back end technical change will not impact user experience here so user will be accessing the microservice same as part 1. There is no change from users perspective.

This is very important point while designing any application. Separation of duties in layers. Layers should not have tight coupling with other layer. This design will make microservice flexible to change one layer/tier without impacting other layer.  

Bonus points - 

We can add initial data with the help of data.sql file. I have added few records so that when we will access the /todos api. We will see some data. Don't get surprise when you see data for /todos GET service so here is source for initial data. Just remember this is memory database and we are using for learning purpose so when we will restart the server, data will also initialise.

Create data.sql file in resource folder of main folder. Copy below content 

insert into todo(id, task,target_date,done)
values(10001, 'Learn JPA', sysdate(), false);

insert into todo(id, task,target_date,done)
values(10002, 'Learn Data JPA', sysdate(), false);

insert into todo(id,task,target_date,done)
values(10003, 'Learn Microservices', sysdate(), false);

Restart the application. 

  .   ____          _            __ _ _

 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.1.RELEASE)

2020-07-21 03:27:00.894  INFO 11004 --- [           main] c.s.microservice.firstmicroservice.App   : Starting App on DESKTOP-BVTFC0U with PID 11004 (D:\intellij\firstmicroservice\target\classes started by vaio in D:\intellij\firstmicroservice)
2020-07-21 03:27:00.918  INFO 11004 --- [           main] c.s.microservice.firstmicroservice.App   : No active profile set, falling back to default profiles: default
2020-07-21 03:27:10.366  INFO 11004 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data repositories in DEFAULT mode.
2020-07-21 03:27:10.675  INFO 11004 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 285ms. Found 1 repository interfaces.
2020-07-21 03:27:11.941  INFO 11004 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2020-07-21 03:27:14.568  INFO 11004 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2020-07-21 03:27:14.593  INFO 11004 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2020-07-21 03:27:14.593  INFO 11004 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.27]
2020-07-21 03:27:15.943  INFO 11004 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2020-07-21 03:27:15.943  INFO 11004 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 14641 ms
2020-07-21 03:27:16.259  INFO 11004 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2020-07-21 03:27:17.286  INFO 11004 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2020-07-21 03:27:17.330  INFO 11004 --- [           main] o.s.b.a.h2.H2ConsoleAutoConfiguration    : H2 console available at '/h2-console'. Database available at 'jdbc:h2:mem:testdb'
2020-07-21 03:27:19.172  INFO 11004 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
2020-07-21 03:27:19.912  INFO 11004 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate Core {5.4.8.Final}
2020-07-21 03:27:21.102  INFO 11004 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.1.0.Final}
2020-07-21 03:27:21.684  INFO 11004 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
Hibernate: 
    
    create table todo (
       id bigint not null,
        done boolean not null,
        target_date timestamp,
        task varchar(255),
        primary key (id)
    )
Hibernate: create sequence hibernate_sequence start with 1 increment by 1
2020-07-21 03:27:25.986  INFO 11004 --- [           main] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2020-07-21 03:27:26.023  INFO 11004 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2020-07-21 03:27:27.808  WARN 11004 --- [           main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2020-07-21 03:27:28.373  INFO 11004 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2020-07-21 03:27:29.750  INFO 11004 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-07-21 03:27:29.767  INFO 11004 --- [           main] c.s.microservice.firstmicroservice.App   : Started App in 33.89 seconds (JVM running for 56.554)


We can access and view memory H2 database on url - http://localhost:8080/h2-console



Testing -

Open Advance Rest Client. We will use that to validate our microservice.


Post Service - 

 
And now if we call Get method again, we can see new todo item in list.



Full code base is uploaded on GitHub. You can download and explore in details.

Upcoming Posts - 

We will have more fun and learning in upcoming weeks. Bookmark this space in your favourite. 
1. Spring boot security Integration
2. Deploy our microservice in docker container.  

Happy Learning!!!





6 comments:

Spring boot - File upload & Download

  Hey Friends,  This is fourth post in  microservice blog. This series is specially designed to learn microservices and various aspect of th...