Hibernate – JPA

pom.xml

				
					<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.0.2</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.brains.jpa.hibernate</groupId>
	<artifactId>jpa-hibernate-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>jpa-hibernate-demo</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>17</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

				
			

These annotions are provided by Hibernate which can track the timestamp of created and updated entries. JPA does not provide these annotations.

@UpdateTimestamp

@CreationTimestamp

				
					package com.brains.jpa.hibernate.jpahibernatedemo.entity;

import java.time.LocalDateTime;

import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AccessLevel;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@Data
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table
public class Course {
	
	@Id
	@GeneratedValue
	private Long id;
	
	private String name;
	
	@UpdateTimestamp
	private LocalDateTime lastUpdatedDate;
	
	@CreationTimestamp
	private LocalDateTime createdDate;
	
	public Course(String name) {
		this.name = name;
	}
}

				
			

application.properties

				
					
spring.datasource.url=jdbc:h2:mem:testdb;NON_KEYWORDS=USER;DB_CLOSE_ON_EXIT=FALSE
spring.h2.console.enabled=true
#spring.data.jpa.repositories.bootstrap-mode=default
spring.jpa.defer-datasource-initialization=true

# Turn Statistics ON
spring.jpa.properties.hibernate.generate_statistics=true
logging.level.org.hibernate.stat=debug
logging.level.org.hibernate=debug
# Show all queries
spring.jpa.show-sql=true

# Format the queries
spring.jpa.properties.hibernate.format_sql=true

# Enable seeing the parameters with query
logging.level.org.hibernate.type=trace
				
			

Normally you should use CURRENT_DATECURRENT_TIMESTAMP, or LOCALTIMESTAMP in H2. They all have standard-compliant implementations and work as expected.

H2 should probably reject SYSDATE and all similar functions in all compatibility modes, with exception for Oracle compatibility mode in which it should be a keyword.

 

data.sql

				
					insert into course(id, name, created_date, last_updated_date) 
values(10001, 'JPA in 5 steps', LOCALTIMESTAMP, LOCALTIMESTAMP);

insert into course(id, name, created_date, last_updated_date) 
values(10002, 'JDBC in 10 steps', LOCALTIMESTAMP, LOCALTIMESTAMP);

insert into course(id, name, created_date, last_updated_date) 
values(10003, 'JPQL in 50 steps', LOCALTIMESTAMP, LOCALTIMESTAMP);
				
			
				
					package com.brains.jpa.hibernate.jpahibernatedemo.repository;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.brains.jpa.hibernate.jpahibernatedemo.entity.Course;

import jakarta.persistence.EntityManager;
import jakarta.transaction.Transactional;

@Repository
@Transactional
public class CourseRepository {

	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
	@Autowired
	EntityManager em;
	
	public Course findById(Long id) {
		return em.find(Course.class, id);
	}
	
	public void deleteById(Long id) {
		Course course = findById(id);
		em.remove(course);
	}
	
	public Course save(Course course) {
		if(course.getId() == null) {
			//insert
			em.persist(course);
		}else {
			//update
			em.merge(course);
		}
		return course;
	}
	
	public void playWithEntityManager() {
		Course course1 = new Course("AngularJs in 100 Steps");
		em.persist(course1);
		
		Course course2 = findById(10001L);
		course2.setName("JPA in 5 steps -- updated");
	}
}

				
			
				
					package com.brains.jpa.hibernate.jpahibernatedemo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.brains.jpa.hibernate.jpahibernatedemo.repository.CourseRepository;

@SpringBootApplication
public class JpaHibernateDemoApplication implements CommandLineRunner {

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

	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
	@Autowired
	private CourseRepository courseRepository;
	
	@Override
	public void run(String... args) throws Exception {
		courseRepository.playWithEntityManager();
	}
}
				
			

Related Tutorials

SpringBoot JPA with H2

JPA is Java Persistence API, is an interface and Hibernate is an implementation of JPA and is an ORM Framework. ORM stands for Object-Relational Mapping

 

 

pom.xml

				
					<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.0.2</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.brains.database</groupId>
	<artifactId>database-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>database-demo</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>17</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

				
			

application.properties

				
					#spring.datasource.url=jdbc:h2:mem:testdb;NON_KEYWORDS=USER
spring.datasource.url=jdbc:h2:mem:public;MODE=MYSQL;DATABASE_TO_UPPER=false;INIT=CREATE SCHEMA IF NOT EXISTS public
spring.h2.console.enabled=true
spring.data.jpa.repositories.bootstrap-mode=default
spring.jpa.defer-datasource-initialization=true

spring.jpa.show-sql=true
				
			

See the UI for the H2 database by typing this url

				
					http://localhost:8080/h2-console
				
			

Add data.sql in the resources folder and it would automatically called at startup. Load some data in the  table by adding some records in the same data.sql file.

data.sql

				
					insert into person (id, name, location, birth_date)
values(10001,'Ranga','Hyderabad', now() );
insert into person (id, name, location, birth_date)
values(10002,'John','Guntur', now() );
insert into person (id, name, location, birth_date)
values(10003,'Ravi','Ahmedabad', now() );
				
			

Create PersonJdbcDao which can interact with the database. Here all the magic happens using Autoconfiguration by SpringBoot. @JdbcTemplate is the class responsible such database interactions.

				
					package com.brains.database.databasedemo.bean;


import java.util.Date;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.NamedQuery;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@Data @AllArgsConstructor @NoArgsConstructor
@NamedQuery(name = "find_all_persons", query = "select p from Person p")
public class Person {

	@Id
	@GeneratedValue
	private int id;
	
	private String name;
	private String location;
	private Date birth_date;
	
	public Person(String name, String location, Date birth_date) {
		super();
		this.name = name;
		this.location = location;
		this.birth_date = birth_date;
	}
}
				
			
				
					package com.brains.database.databasedemo.repository;

import java.util.List;

import org.springframework.stereotype.Repository;

import com.brains.database.databasedemo.bean.Person;

import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.TypedQuery;
import jakarta.transaction.Transactional;

@Repository
@Transactional
public class PersonJpaRepository {

	@PersistenceContext
	EntityManager entityManager;
	
	public List<Person> findAll(){
		TypedQuery<Person> personNamedQuery = entityManager.createNamedQuery("find_all_persons", Person.class);
		return personNamedQuery.getResultList();
	}
	
	public Person findById(int id) {
		return entityManager.find(Person.class, id);
	}
	
	public Person update(Person person) {
		return entityManager.merge(person);
	}
	
	public Person insert(Person person) {
		return entityManager.merge(person);
	}
	
	public void delete(int id) {
		Person person = findById(id);
		entityManager.remove(person);
	}
}

				
			

Extend the main applicatino with CommandLineRunner so that run() method can be executed while application startup.

				
					package com.brains.database.databasedemo;

import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.brains.database.databasedemo.bean.Person;
import com.brains.database.databasedemo.repository.PersonJpaRepository;

@SpringBootApplication
public class SpringJpaDemoApplication implements CommandLineRunner {

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

	@Autowired
	PersonJpaRepository jpaRepository;

	private Logger logger = LoggerFactory.getLogger(this.getClass());

	@Override
	public void run(String... args) throws Exception {
		logger.info("Peson found: -> {}", jpaRepository.findById(10002));
		logger.info("Insert new person -> {}", jpaRepository.insert(new Person("Suresh", "Ahmedabad", new Date())));
		jpaRepository.delete(10001);
		
		logger.info("All persons: -> {}", jpaRepository.findAll());
	}
}
				
			

Running the Application

				
					2023-02-21T00:28:37.518+05:30  INFO 26412 --- [           main] SpringJpaDemoApplication$$SpringCGLIB$$0 : Peson found: -> Person(id=10002, name=John, location=Guntur, birth_date=2023-02-21 00:28:37.298462)
Hibernate: select next value for person_seq
Hibernate: insert into person (birth_date, location, name, id) values (?, ?, ?, ?)
2023-02-21T00:28:37.527+05:30  INFO 26412 --- [           main] SpringJpaDemoApplication$$SpringCGLIB$$0 : Insert new person -> Person(id=1, name=Suresh, location=Ahmedabad, birth_date=2023-02-21 00:28:37.518)
Hibernate: select p1_0.id,p1_0.birth_date,p1_0.location,p1_0.name from person p1_0 where p1_0.id=?
Hibernate: delete from person where id=?
Hibernate: select p1_0.id,p1_0.birth_date,p1_0.location,p1_0.name from person p1_0
2023-02-21T00:28:37.551+05:30  INFO 26412 --- [           main] SpringJpaDemoApplication$$SpringCGLIB$$0 : All persons: -> [Person(id=1, name=Suresh, location=Ahmedabad, birth_date=2023-02-21 00:28:37.518), Person(id=10002, name=John, location=Guntur, birth_date=2023-02-21 00:28:37.298462), Person(id=10003, name=Ravi, location=Ahmedabad, birth_date=2023-02-21 00:28:37.298631)]

				
			

Related Tutorials

SpringBoot JDBC with H2

Adding the dependencies of JDBC and H2 in the pom file.

 

 

pom.xml

				
					<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.0.2</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.brains.database</groupId>
	<artifactId>database-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>database-demo</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>17</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

				
			

application.properties

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

See the UI for the H2 database by typing this url

				
					http://localhost:8080/h2-console
				
			

Add data.sql in the resources folder and it would automatically called at startup. Load some data in the  table by adding some records in the same data.sql file.

data.sql

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

// add few records
insert into person (id, name, location, birth_date)
values(10001,'Ranga','Hyderabad', now() );
insert into person (id, name, location, birth_date)
values(10002,'John','Guntur', now() );
insert into person (id, name, location, birth_date)
values(10003,'Ravi','Ahmedabad', now() );
				
			

Create PersonJdbcDao which can interact with the database. Here all the magic happens using Autoconfiguration by SpringBoot. @JdbcTemplate is the class responsible such database interactions.

				
					package com.brains.database.databasedemo.bean;


import java.util.Date;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data @AllArgsConstructor @NoArgsConstructor
public class Person {

	private int id;
	private String name;
	private String location;
	private Date birth_date;
}

				
			
				
					package com.brains.database.databasedemo.bean;


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data @AllArgsConstructor @NoArgsConstructor
public class CustomPerson {

	private int id;
	private String name;
}

				
			
				
					package com.brains.database.databasedemo.repository;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import com.brains.database.databasedemo.bean.Person;
import com.brains.database.databasedemo.bean.CustomPerson;

@Repository
public class PersonJdbcDao {

	@Autowired
	JdbcTemplate jdbcTemplate;
	
	class PersonRowMapper implements RowMapper<CustomPerson>{

		@Override
		public CustomPerson mapRow(ResultSet rs, int rowNum) throws SQLException {
			CustomPerson person = new CustomPerson();
			person.setId(rs.getInt("id"));
			person.setName(rs.getString("name"));
			return person;
		}
	}
	
	public List<CustomPerson> findAllUsingRowMapper(){
		return jdbcTemplate.query("select * from person", 
				new PersonRowMapper()); 
	}
	
	public List<Person> findAll(){
		return jdbcTemplate.query("select * from person", 
				new BeanPropertyRowMapper<Person>(Person.class)); 
	}

	
	public Person getPersonById(int id) {
		return jdbcTemplate.queryForObject("select * from person where id = ?", 
				new Object[] {id},
				new BeanPropertyRowMapper<Person>(Person.class));
	}
	
	public int deleteById(int id) {
		return jdbcTemplate.update("delete from person where id =?", 
				new Object[] {id}
				);
	}
	
	public int insertPerson(Person person) {
		return jdbcTemplate.update("insert into person (id, name, location, birth_date)\n"
				+ "values(?,?,?,?)",
				new Object[] {
						person.getId(), person.getName(), 
						person.getLocation(), 
						new Timestamp(person.getBirth_date().getTime())});
	}
	
	public int updatePerson(Person person) {
		return jdbcTemplate.update(
				"update person \n"
				+ " set name = ?, location = ?, birth_date = ? \n"
				+ " where id = ? ",
				new Object[] {
						person.getName(), 
						person.getLocation(), 
						new Timestamp(person.getBirth_date().getTime()),
						person.getId()}
				);
	}
}

				
			

Extend the main applicatino with CommandLineRunner so that run() method can be executed while application startup.

				
					package com.brains.database.databasedemo;

import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.brains.database.databasedemo.bean.Person;
import com.brains.database.databasedemo.repository.PersonJdbcDao;

@SpringBootApplication
public class DatabaseDemoApplication implements CommandLineRunner {

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

	@Autowired
	PersonJdbcDao jdbcDao;
	
	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
	@Override
	public void run(String... args) throws Exception {
		logger.info("All users using RowMapper: -> {}", jdbcDao.findAllUsingRowMapper());
		logger.info("All users using BeanPropertyRowMapper: -> {}", jdbcDao.findAll());
		
		logger.info("Peson found: -> {}", jdbcDao.getPersonById(10002));
		logger.info("Delete Peson: -> {}", jdbcDao.deleteById(10002));
		
		logger.info("Insert new person -> {}", jdbcDao.insertPerson(new Person(10004, "Suresh", "Ahmedabad", new Date())));
		logger.info("Update Person id 10003 -> {}", jdbcDao.updatePerson(new Person(10003, "Aman", "Ahmedabad", new Date())));
		logger.info("All users: -> {}", jdbcDao.findAll());
	}
}

				
			

Running the Application

				
					2023-02-20T20:16:23.124+05:30  INFO 120598 --- [           main] .DatabaseDemoApplication$$SpringCGLIB$$0 : All users using RowMapper: -> [CustomPerson(id=10001, name=Ranga), CustomPerson(id=10002, name=John), CustomPerson(id=10003, name=Ravi)]
2023-02-20T20:16:23.129+05:30  INFO 120598 --- [           main] .DatabaseDemoApplication$$SpringCGLIB$$0 : All users using BeanPropertyRowMapper: -> [Person(id=10001, name=Ranga, location=Hyderabad, birth_date=2023-02-20 20:16:22.657722), Person(id=10002, name=John, location=Guntur, birth_date=2023-02-20 20:16:22.659073), Person(id=10003, name=Ravi, location=Ahmedabad, birth_date=2023-02-20 20:16:22.659391)]
2023-02-20T20:16:23.142+05:30  INFO 120598 --- [           main] .DatabaseDemoApplication$$SpringCGLIB$$0 : Peson found: -> Person(id=10002, name=John, location=Guntur, birth_date=2023-02-20 20:16:22.659073)
2023-02-20T20:16:23.144+05:30  INFO 120598 --- [           main] .DatabaseDemoApplication$$SpringCGLIB$$0 : Delete Peson: -> 1
2023-02-20T20:16:23.145+05:30  INFO 120598 --- [           main] .DatabaseDemoApplication$$SpringCGLIB$$0 : Insert new person -> 1
2023-02-20T20:16:23.148+05:30  INFO 120598 --- [           main] .DatabaseDemoApplication$$SpringCGLIB$$0 : Update Person id 10003 -> 1
2023-02-20T20:16:23.149+05:30  INFO 120598 --- [           main] .DatabaseDemoApplication$$SpringCGLIB$$0 : All users: -> [Person(id=10001, name=Ranga, location=Hyderabad, birth_date=2023-02-20 20:16:22.657722), Person(id=10003, name=Aman, location=Ahmedabad, birth_date=2023-02-20 20:16:23.145), Person(id=10004, name=Suresh, location=Ahmedabad, birth_date=2023-02-20 20:16:23.144)]

				
			

Related Tutorials