Skip to content

  • Home
  • Core Java
    • Write Your Own Immutable Class In Java
    • Write Your Own Singleton Class In java
    • Java Concurrent Package
    • Java Stream Revisited
    • Print odd and even numbers using thread
    • SOLID principles
    • Comparable Vs Comparator
    • Sort HashMap/TreeMap based on value
    • Deep and Shallow Copy in Java with examples
    • Find the frequency of each character in a String
    • How to avoid duplicate Employee objects in HashSet ?
  • Spring
    • Loose Coupling & Dependency Injection
    • Bean Scope
    • Spring Bean Lifecycle
    • IoC Container Vs Application Context Vs Bean Factory
    • @Component Vs @Service @Repository Vs @Controller
    • How to read properties file in Spring
    • Spring AOP (Aspect Oriented Programming)
    • @Component Vs @Bean in Spring
    • Exception Handling in SpringBoot
    • XML configuration Vs Annotations configuration in Spring
    • Spring Data JPA
    • Spring Data REST
  • Spring Security
    • Spring Security with Form, Basic and JWT
    • Security Configuration in Spring Boot Apps
    • Security Protocols & Frameworks
    • Okta OAuth 2.0 SSO with Springboot
    • Spring Boot 2.x Security using Username Password
    • Spring Boot 2.x Security using JWT
    • Spring Boot 3.x Security using Username Password
    • Spring Boot 3.x Security using JWT
  • Microservices
    • Spring Cloud Config (Server & Client)
    • Spring Boot Microservices Tutorial (Part 1 of 2)
    • Spring Boot Microservices Tutorial (Part 2 of 2)
    • Circuit Breaker – Resilience4j
    • The Twelve-Factor App Principles
  • Event Driven Microservices
    • What is Event Driven Microservice ?
    • What is Saga Design Pattern ?
    • What is CQRS Design Pattern ?
  • Spring AI
    • ChatGPT API + SpringBoot Integration
  • Hibernate & JPA
    • JPA vs JDBC
    • CRUD Example Using Spring Boot JPA + H2 + Gradle
    • MongoDB Atlas With Spring Boot Example
    • Transaction Management
    • Relationships in JPA & Hibernate
    • Hibernate First & Second Level Cache
    • Spring Boot Flyway Postgres
  • DevOps
    • What is Devops ?
    • Docker
    • Kubernetes (K8S)
    • Jenkins
    • Infrastructure As Code
  • Functional Programming
    • Functional Programming Vs Structured Programming
    • Java 8 Programs For Interview
    • Predicate, Function, Consumer and Supplier in Java 8
    • Sort a List having Employee objects using Java 8
    • Find Employee from List using Java 8
  • AWS
    • AWS S3
    • AWS EC2
    • EC2 Solutions Architecting
    • How to create an EC2 instance ?
    • How to connect to AWS EC2 instance ?
    • Deploy application to AWS
    • AWS Lambda Java Tutorial
    • Spring Cloud Functions
    • How to Start/Stop AWS ECS automatically using Java Spring?
    • Container Solution in AWS
    • AWS SQS, SNS, MQ and Kinesis
    • Databases in AWS
    • AWS VPC: Peering, Endpoint, VPN, Gateways- Internet, NAT, DX
    • Machine Learning in AWS
    • Storage Solutions in AWS
    • AWS ASG (Auto Scaling Group)
  • AWS Certifications
    • SAA-C03
      • Design Cost-Optimized Architectures
    • AWS Certified Solution Architect-Associate
      • Question 1
  • Kafka
    • Apache Kafka
    • Kafka Producer & Consumer Example Using Spring boot & Conduktor
  • Angular
    • Angular Tutorial – Part 1
    • Angular Tutorial – Part 2
  • Miscellaneous
    • How to add a project to Git/GitHub/GitLab
    • How to Clone a project from Git/GitLab using Git Bash
    • How to query Oracle tables based on some date ?
    • How to highlight text in WordPress ?
    • How to add Page Jumps in WordPress page ?
  • Interview Preparation
    • Core java interview questions
    • Java Threads Interview Questions
  • Contact Me
  • Toggle search form

JPA vs JDBC

Before comparing between JPA and JDBC, lets see the journey from JDBC to JPA. For that we will first see the non-spring JDBC, then Spring JDBC, then Hibernate and finally Spring Data JPA.

2 decades ago when we started our java programming journey we used to write pure JDBC calls to connect to database. As the time passes by, we migrated to Hibernate, and now we use JPA in the real world applications.

JDBC Vs Spring JDBC:

 In the earlier days (pre-spring boot era) we used to write the JDBC code something like below:

Connection connection = datasource.getConnection();

		PreparedStatement st = connection.prepareStatement(
				"SELECT * FROM TODO where user=?");

		st.setString(1, user);

		ResultSet resultSet = st.executeQuery();
		List<Todo> todos = new ArrayList<>();

		while (resultSet.next()) {

			Todo todo = new Todo(resultSet.getInt("id"),
					resultSet.getString("user"),
					resultSet.getString("desc"),
					resultSet.getTimestamp("target_date"),
					resultSet.getBoolean("is_done"));
			todos.add(todo);
		}

		st.close();

		connection.close();

And, here is the sample Spring JDBC code:

@Repository
public class PersonJbdcDao {

	@Autowired
	JdbcTemplate jdbcTemplate;
	
	public List<Person> someName() {
		return jdbcTemplate.query("select * from person", new BeanPropertyRowMapper(Person.class));
	}

So below are the benefits of using the Spring JDBC:

  1. Lesser code.
  2. Makes you to do less mistakes- you don’t have to worry for connection closing, exception handling, etc.

Lets do a demo for Spring JDBC first.
In the subsequent section we will see Hibernate and then JPA.

Spring JDBC demo:

Lets create an Spring Boot project with below dependencies from Spring Initializr:

  • Spring Web
  • JDBC
  • H2

Since we are using H2 in-memory database, add below content in application.properties:

spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb
spring.data.jpa.repositories.bootstrap-mode=default

Run the main java class. You can see this URL in the log: /h2-console

So hit this url: http://localhost:8080/h2-console

Verify that the JDBC URL given as jdbc:h2:mem:testdb

Username: sa
Password:

Click Connect.

You will see the h2-console:

Now if you see there is no tables in the database.

Now, we will use the spring auto-configuration feature to create some table and populate some data to the database. For that, Create a file called data.sql in the /resources folder and add below contents to it:

create table person
(
	id integer not null,
	name varchar(255),
	birth_date timestamp,
	primary key(id)
);

Once you restart the application you can see the Person table in the database, although you won’t see any data in it.

If you want to populate some rows to this table then you can add some insert queries to the same data.sql file like below:

create table person
(
	id integer not null,
	name varchar(255),
	birth_date timestamp,
	primary key(id)
);

insert into person values(1001,'Prasanna',sysdate());
insert into person values(1002,'Padma',sysdate());
insert into person values(1003,'Sarojini',sysdate());

P.S.: Everytime you restart the application the previous data will be gone, because its an in-memory database.

Now lets write some Spring JDBC stuffs which you are looking for right now:

Create an entity class: Person.java. Make sure to have an no-arg constructor otherwise it will give run time error.

public class Person {
	private int id;
	private String name;
	private Date birthDate;
	
	public Person() {		
	}
	
	public Person(int id, String name, Date birthDate) {
		super();
		this.id = id;
		this.name = name;
		this.birthDate = birthDate;
	}
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Date getBirthDate() {
		return birthDate;
	}
	public void setBirthDate(Date birthDate) {
		this.birthDate = birthDate;
	}

	@Override
	public String toString() {
		return "\n Person [id=" + id + ", name=" + name + ", birthDate=" + birthDate + "]";
	}
}

Create a Dao class, give any name to the method:

@Repository
public class PersonJdbcDao {
	
	@Autowired
	JdbcTemplate jdbcTemplate;
	
	public List findAll() {
		return jdbcTemplate.query("select * from Person", new BeanPropertyRowMapper(Person.class));
	}

	public Person findById(int id) {
		return jdbcTemplate.queryForObject("select * from Person where id= ?", new Object[] {id} ,new BeanPropertyRowMapper<Person>(Person.class));
	}
}

Here we had used query() and queryForObject() of JdbcTemplate to fetch all and individual records respectively.

BeanPropertyRowMapper is used to convert a table row into a new instance of the specified mapped target class.

In the main class:

@SpringBootApplication
public class HibernateJpaApplication implements CommandLineRunner{
	
	private Logger logger=LoggerFactory.getLogger(this.getClass());
	
	@Autowired
	PersonJdbcDao dao;
	
	public static void main(String[] args) {
		SpringApplication.run(HibernateJpaApplication.class, args);
	}

	@Override
	public void run(String... args) throws Exception {
		//logger.info("All users ---> {}" + dao.findAll());
		logger.info("User ---> {}" + dao.findById(1001));		
	}
}

ApplicationRunner and CommandLineRunner interfaces will lets you to execute the code after the Spring Boot application is started. You can use these interfaces to perform any actions immediately after the application has started.

The above code setup will fetch records from the table, using Spring JDBC way.

Springboot Autoconfiguration:

In the above demo we had just @Autowired the JdbcTemplate, but how does Spring know about the database connection- like what and where is the database etc.

This is the magic of Spring Boot Auto Configuration- it looks for what are available in its classpath and automatically configures that.

To see the AUTO-CONFIGURATION REPORT in the log just add below line in application.properties:

logging.level.root=debug

Then you will see below lines of code in the console:

Spring Boot JPA

Now lets see the Spring Boot JPA demo.
To replace the Spring JDBC code with JPA code, below changes you need to do:

Add below dependency to the project (available in Spring Initializr):

  • Spring Data JPA

By adding above dependency, these 3 dependencies are added- JPA, Hibernate and Spring Data JPA

Add below annotations to the bean:
@Entity – Its like bean++
@Id – to make it primary key
@GeneratedValue – to auto generate the id.

@Entity
public class Person {

	@Id
	@GeneratedValue
	private int id;

	private String name;
	private String location;

And create a new repository class:

@Repository
@Transactional
public class PersonJpaRepository {

	// connect to the database
	@PersistenceContext
	EntityManager entityManager;
	
	public Person findById(int id) {
		return entityManager.find(Person.class, id);// JPA
	}

EntityManager is similar to Session in Hibernate. The way we write session.save() in Hibernate we will call entityManager.persist() in JPA.

If you are using Spring Boot 2.5.0 or Greater, add the following property to application.properties

spring.jpa.defer-datasource-initialization=true

Why do you need to make the change?

By default, data.sql scripts are now run before Hibernate is initialized. This aligns the behaviour of basic script-based initialization with that of Flyway and Liquibase. If you want to use data.sql to populate a schema created by Hibernate, set spring.jpa.defer-datasource-initialization to true. While mixing database initialization technologies is not recommended, this will also allow you to use a schema.sql script to build upon a Hibernate-created schema before it’s populated via data.sql.

Now if you run the application you will get an error saying: Person table already exists. Why so ?

Because, Schema Update which is a Hibernate feature, will automatically create a table for us for an in-memory database. Schema Update will be triggered by Springboot auto-configuration. Springboot sees @Entity annotation and do all these magic.

So, remove the create table query from data.sql file. But you have to keep the insert table query in data.sql as it is.

So, below will be the data.sql:

insert into person(id,name,birth_date) values(1001,'Prasanna',sysdate());
insert into person(id,name,birth_date) values(1002,'Padma',sysdate());
insert into person(id,name,birth_date) values(1003,'Sarojini',sysdate());

If you want to see the SQL query in the console that is fired, add this in application.properties:

spring.jpa.show-sql=true

P.S.: There is a lot of confusion between JPA and Hibernate. JPA is an specifications, its not an implementation. Hibernate is an implementation of JPA. Spring JPA is another implementation of JPA, it came to the market long after Hibernate became popular. Whenever you add spring-boot-starter-data-jpa (Spring Data JPA) artifactId from Spring Initialzr, you get both hibernate-core and spring-data-jpa artifactId in your code. In all the examples in this section we would be talking about JPA, but internally we would be doing Hibernate calls. In the logs also you can see Hibernate instances everywhere like below:

org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect

Although the style of code that we had used is not specific to Hibernate, its rather like JPA style, for eg., here we used EntityManager instead of Session, PersistenceContext instead of SessionFactory.
Later part of this tutorial series we will see how to use Spring Data JPA as well.
But the question is, what is the benefit of using JPA style of code if we are using hibernate internally, why not hibernate ? The answer is, if tomorrow if we want to change our ORM to some other vendor than hibernate then it won’t have any problem.

Implementing other CRUD operations in JPA repository:

Implementing insert and update JPA repository:

For implementing insert and update to a JPA repository you need to call a single method called – merge()

Below would be the implementation:

	public Person2 insertUpdate(Person2 person) {
		return entityManager.merge(person);
	}

The object that you are passing, JPA will first check whether that object exists in the DB, if it doesn’t find it it will insert, else it will update.

Alternatively, for insert only you can use persist() as well.

Implement deleteById in JPA repository:

You need to use this method: remove(). Just call your findById() inside this method.

	public void deleteById(int id) {		
		entityManager.remove(findById(id));
	}

Implement findAll in JPARepository

For this you need to use HQL (Hibernate Query Language), infact JPQL(Jpa Persistent Query Language). In JPQL you will be using a NamedQuery.

	public List findAll() {
		return entityManager.createNamedQuery("find_all").getResultList();
	}

In the Person entity class you need to add below annotation at the top:

@NamedQuery(name="find_all", query="select p from Person2 p")

More about EntityManager & PersistenceContext

EntityManager is an interface to the PersistenceContext, its like Session in Hibernate. And PersistenceContext is an block of memory which keeps track of all entities, its like a SessionFactory in Hibernate.
What is the difference between @PersistenceContext and EntityManagerFactory ?
Both are the factory, in the former one the container takes care of the lifecycle of the bean and in the later one the programmer (you) takes care of the lifecycle.

@PersistenceContext(unitName ="some name")
private EntityManager entityManager;
EntityManagerFactory emf = Persistence.createEntityManagerFactory("some name");
EntityManager em = emf.createEntityManager();

In the above steps we had seen that what is the usage of persist() method. Basically its for saving any data to DB.
Suppose we call the persist() method and after that you change some value in the object. Do you think the value will be updated in the DB, although you have not requested to persist the data ?

Person person=new Person("Bangalore",new Date());
entityManager.persist(person);
person.setName("Some updated name");

Yes, it would be saved. This magic happened because the EntityManager. When EntityManager sees the @Transactional in the Entity class it do all things in a transaction

One can see the below 2 lines in the console log, once we execute the above code:

Hibernate: insert into person (birth_date, name, id) values (?, ?, ?)
Hibernate: update person set birth_date=?, name=? where id=?

flush()

flush() will do explicit commit of the changes.
Below 2 block of code- one with and other without the flush(), will give the same result:

		Person person=new Person("Bangalore",new Date());	
		entityManager.persist(person);
		person.setName("some updated name");
		Person person=new Person("Bangalore",new Date());	
		entityManager.persist(person);
		person.setName("some updated name");
		entityManager.flush();

Why? The first block will commit the changes once the transaction is complete. The 2nd block will also do the commit on the call of the flush() along with the completion of transaction.

detach()

When you detach some object from the EntityManager session, it wouldn’t be part of the DB changes. Before doing detach(), try to flush() other changes, else you will get runtime exception.

Lets see the below code, here we are basically doing 4 things- persisting person1 (and flushing it), updating person1 (and flushing it), persisting person2 (and flushing it), updating person2 (and flushing it). Before doing the 4th task we are doing detach(). Can you guess the result ?

    Person person=new Person("Tom 1",new Date()); 
    entityManager.persist(person);
    entityManager.flush(); //will save successfully

    person.setName("Tom 11");
    entityManager.flush(); //will update successfully

    Person person2=new Person("Tom 2",new Date());   
    entityManager.persist(person2);
    entityManager.flush(); //will save successfully

    entityManager.detach(person2); //detached

    person2.setName("Tom 22"); //this data will be lost     
    entityManager.flush(); //Will not save.

Of course, the 4th task (updation) will not work.

clear()

This works similar to detach(), it will remove any object from the Entity Manager object. The only difference which I have seen is it it works fine without the use of the flush().

refresh()

This will fetch data from the DB and will override the changes on the object.

Copyright © 2025 .

Powered by PressBook Blog WordPress theme