🖍️
Developer Note
  • Welcome
  • Git
    • Eslint & Prettier & Stylelint & Husky
  • Programming Language
    • JavaScript
      • Script Async vs Defer
      • Module
      • Const VS Let VS Var
      • Promise
      • Event Loop
      • Execution Context
      • Hoisting
      • Closure
      • Event Buddling and Capturing
      • Garbage Collection
      • This
      • Routing
      • Debounce and Throttle
      • Web Component
      • Iterator
      • Syntax
      • String
      • Array
      • Object
      • Proxy & Reflect
      • ProtoType
      • Class
      • Immutability
      • Typeof & Instanceof
      • Npm (Node package manager)
    • TypeScript
      • Utility Type
      • Type vs Interface
      • Any vs Unknown vs Never
      • Void and undefined
      • Strict Mode
      • Namespace
      • Enum
      • Module
      • Generic
    • Python
      • Local Development
      • Uv
      • Asyncio & Event loop
      • Context Manager
      • Iterator & Generator
      • Fast API
      • Pydantic & Data Class
    • Java
      • Compilation and Execution
      • Data Type
      • Enumeration
      • Data Structure
      • Try Catch
      • InputStream and OutputStream
      • Concurrent
      • Unicode Block
      • Build Tools
      • Servlet
      • Java 8
  • Coding Pattern
    • MVC vs MVVM
    • OOP vs Functional
    • Error Handling
    • MVC vs Flux
    • Imperative vs Declarative
    • Design Pattern
  • Web Communication
    • REST API
      • Web Hook
      • CORS issue
    • HTTPS
    • GraphQL
      • REST API vs GraphQL
      • Implementation (NodeJS + React)
    • Server-Sent Event
    • Web Socket
    • IP
    • Domain Name System (DNS)
  • Frontend
    • Progressive Web App (PWA)
    • Single Page & Multiple Page Application
    • Search Engine Optimiaztion (SEO)
    • Web bundling & Micro-frontend
      • Webpack
        • Using Webpack to build React Application
        • Using Webpack to build react library
      • Vite
      • Using rollup to build react library
      • Implementing micro frontend
    • Web Security
      • CSRF & Nonce
      • XSS
      • Click hijacking
    • Cypress
    • CSS
      • Core
        • Box Model
        • Inline vs Block
        • Flexbox & Grid
        • Pseudo Class
        • Position
      • Tailwind CSS
        • Shadcn
      • CSS In JS
        • Material UI
    • React
      • Core
        • Component Pattern
        • React Lazy & Suspense
        • React Portal
        • Error Boundary
        • Rendering Methods
        • Environment Variable
        • Conditional CSS
        • Memo
        • Forward Reference
        • High Order Component (HOC) & Custom Hook
        • TypeScript
      • State Management
        • Redux
        • Recoil
        • Zustand
      • Routing
        • React Router Dom
      • Data Fetching
        • Axios & Hook
        • React Query
        • Orval
      • Table
        • React Table
      • Form & Validation
        • React Hook Form
        • Zod
      • NextJS
        • Page Router
        • App Router
      • React Native
    • Angular
    • Svelte
      • Svelte Kit
  • Backend
    • Cache
      • Browser Cache
      • Web Browser Storage
      • Proxy
      • Redis
    • Rate limit
    • Monitoring
      • Logging
      • Distributed Tracing
    • Load Test
    • Encryption
    • Authentication
      • Password Protection
      • Cookie & Session
      • JSON Web Token
      • SSO
        • OAuth 2.0
        • OpenID Connect (OIDC)
        • SAML
    • Payment
      • Pre-built
      • Custom
    • File Handling
      • Upload & Download (Front-end)
      • Stream & Buffer
    • Microservice
      • API Gateway
      • Service Discovery
      • Load Balancer
      • Circuit Breaker
      • Message Broker
      • BulkHead & Zipkin
    • Elastic Search
    • Database
      • SQL
        • Group By vs Distinct
        • Index
        • N + 1 problem
        • Normalization
        • Foreign Key
        • Relationship
        • Union & Join
        • User Defined Type
      • NOSQL (MongoDB)
      • Transaction
      • Sharding
      • Lock (Concurrency Control)
    • NodeJS
      • NodeJS vs Java Spring
      • ExpressJS
      • NestJS
        • Swagger
        • Class Validator & Validation Pipe
        • Passport (Authentication)
      • Path Module
      • Database Connection
        • Integrating with MYSQL
        • Sequalize
        • Integrating with MongoDB
        • Prisma
        • MikroORM
        • Mongoose
      • Streaming
      • Worker Thread
      • Passport JS
      • JSON Web Token
      • Socket IO
      • Bull MQ
      • Pino (Logging)
      • Yeoman
    • Spring
      • Spring MVC
      • Spring REST
      • Spring Actuator
      • Aspect Oriented Programming (AOP)
      • Controller Advice
      • Filter
      • Interceptor
      • Concurrent
      • Spring Security
      • Spring Boot
      • Spring Cloud
        • Resilience 4j
      • Quartz vs Spring Batch
      • JPA and Hibernate
      • HATEOS
      • Swagger
      • Unit Test (Java Spring)
      • Unit Test (Spring boot)
  • DevOp
    • Docker
    • Kubernetes
      • Helm
    • Nginx
    • File System
    • Cloud
      • AWS
        • EC2 (Virtual Machine)
        • Network
        • IAM
          • Role-Service Binding
        • Database
        • Route 53
        • S3
        • Message Queue
        • Application Service
        • Serverless Framework
        • Data Analysis
        • Machine Learning
        • Monitoring
        • Security
      • Azure
        • Identity
        • Compute Resource
        • Networking
        • Storage
        • Monitoring
      • Google Cloud
        • IAM
          • Workload Identity Federation
        • Compute Engine
        • VPC Network
        • Storage
        • Kubernetes Engine
        • App Engine
        • Cloud function
        • Cloud Run
        • Infra as Code
        • Pub/Sub
    • Deployment Strategy
    • Jenkins
    • Examples
      • Deploy NextJS on GCP
      • Deploy Spring on Azure
      • Deploy React on Azure
  • Domain Knowledge
    • Web 3
      • Blockchain
      • Cryptocurrency
    • AI
      • Prompt
      • Chain & Agent
      • LangChain
      • Chunking
      • Search
      • Side Products
Powered by GitBook
On this page
  • Introduction
  • Object-Relational-Mapping (ORM)
  • JPA (Java Persistence API)
  • Hibernate
  • Entity Manager
  • Introduction
  • Life Cycle
  • Pre-Action
  • Modal
  • Repository
  • Basic Operation (CRUD)
  • Insert
  • Update
  • Delete
  • One-To-One Relationship
  • SQL
  • Modals
  • Service
  • One-To-Many Relationship
  • SQL
  • Modals
  • Service
  • Many-To-Many Relationship
  • SQL
  • Modals
  • Service
  • Customize Repository
  • Method 1
  • Method 2
  • Reference
  • Transaction
  • Introduction
  • Implementation
  • Propagation

Was this helpful?

  1. Backend
  2. Spring

JPA and Hibernate

PreviousQuartz vs Spring BatchNextHATEOS

Last updated 1 year ago

Was this helpful?

Introduction

Object-Relational-Mapping (ORM)

  • Initially, the property of java object is unmatched with the table of database, and we use JDBC directly to connect to the database which require us to write sql command for many times which will be time-consuming

  • So , we need Object-Relational-Mapping (ORM) to allow the conversion of data between java object and table of database. We can access to our target java object, and then converse the suitable data format automatically and store into database.

JPA (Java Persistence API)

  • It is a standard that providing method of insert, delete, update

Hibernate

  • Hibernate is one of the solution of ORM and is a hidden implementation of JPA interface, so as to convert the method of JPA into relative SQL command to access the table

  • Hibernate will create the sql command based the object, do the work of JDBC to connect to database

Entity Manager

Introduction

  • EntityManager is part of the Java Persistence API. Chiefly, it implements the programming interfaces and lifecycle rules defined by the JPA 2.0 specification.

  • It implements the hidden logic of JPA repository to manage the state of entity

Life Cycle

There are mainly four states of the entity :

  1. Transient State

  2. Persistent State

  3. Detached State

  4. Removed State

Transient State

Student student = new Student("email@dot.com");

Persistent State

  • Once the object is connected with the Hibernate Session then the object moves into the Persistent State.

  • In this state. each object represents one row in the database table. Therefore, if we make any changes in the data then hibernate will detect these changes and make changes in the database table.

Student student = new Student("test@email.com");
// Make changes and see if the data is updated automatically
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction tx = entityManager.getTransaction();
tx.begin();
entityManager.persist(student);
//purposely made changes - did not manually update
student.setEmail("updated_email@gmail.com");
Long persistedId = student.getId();
tx.commit();
entityManager.close();

Detached State

  • For converting an object from Persistent State to Detached State, we either have to close the session or we have to clear its cache. As the session is closed here or the cache is cleared, then any changes made to the data will not affect the database table.

tx.begin();
student = entityManager.find(Student.class, persistedId);
tx.commit();
entityManager.close();
System.out.println("Persisted Student: " + student);
student.setEmail("updated_again@gmail.com");

Removed State

  • In the removed state, when the entity object is deleted from the database then the entity object is known to be in the removed state.

//Remove an Object from the database
entityManager = entityManagerFactory.createEntityManager();
tx = entityManager.getTransaction();
tx.begin();
student = entityManager.find(Student.class, persistedId);
entityManager.remove(student);
tx.commit();
entityManager.close();

Pre-Action

  • Install Dependencies

	<!-- MySQL Database Driver -->
	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<scope>runtime</scope>
	</dependency>
	
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-data-jpa</artifactId>
	</dependency>
	
  • Enter the configuration of database

spring.jpa.hibernate.ddl-auto = update
spring.datasource.url = jdbc:mysql://localhost:3306/test?useUnicode=yes&characterEncoding=UTF-8
spring.datasource.username = root
spring.datasource.password = 1234

Modal

  • Setup a modal of the java object which will be used to map to its relative table in database

@Entity(name = "student_info")
@DynamicInsert
@DynamicUpdate
public class Student
{
	@Id
	//@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "id")
	private String studentId;

	@Column(name = "name")
	private String studentName;

	@Column(name = "age")
	private Integer studentAge;

	@Column(name = "class")
	private String studentClass;

	public Student()
	{
	}

	public String getStudentId() {
		return studentId;
	}

	public void setStudentId(String studentId) {
		this.studentId = studentId;
	}

	public String getStudentName() {
		return studentName;
	}

	public void setStudentName(String studentName) {
		this.studentName = studentName;
	}

	public Integer getStudentAge() {
		return studentAge;
	}

	public void setStudentAge(Integer studentAge) {
		this.studentAge = studentAge;
	}

	public String getStudentClass() {
		return studentClass;
	}

	public void setStudentClass(String studentClass) {
		this.studentClass = studentClass;
	}
}
  • @Entity: To label a class which will be used to mapped to its relational table, but also occupy columns and row to the table

  • @Column: As the name of column of table may not be the same as the class, it should be used top label the variable so as to map to its relational column with the name provided

  • @Id: To label the variable as a primary key

  • @GeneratedValue : It is mainly divided into 3 different strategies - Identity, Auto, Sequence, Table

  • Identity: The primary key of SQL have set the default value or auto-increment

  • Auto: No need do a setter and getter for primary key, the primary key will increased automatically and make sure the primary key of sql must be integer type

  • Not set: The primary key is a string type and set by setter

Repository

  • An interface which contains the method of JPA to access the table , we can also define the custom method on there.

@Repository
public interface StudentRepository extends JpaRepository<Student,String>
{
   Student getStudentByStudentName(String name);
}
  • 1st parameter is a entity class

  • 2nd parameter is the type of primary key

Basic Operation (CRUD)

Insert

	@Override
	public void insertNewStudent(String name, Integer age, String studentClass){
		Student student = new Student();
		String studentId = UUID.randomUUID().toString();
		student.setStudentId(studentId);
		student.setStudentName(name);
		student.setStudentAge(age);
		student.setStudentClass(studentClass);
		studentRepository.save(student);
	}

Update

@Override
	public void updateStudentName(String oldName, String newName){
		Student student = studentRepository.getStudentByStudentName(oldName);
		student.setStudentName(newName);
		studentRepository.save(student);
	}

Delete

@Override
	public void deleteStudentId(String id){
		studentRepository.deleteById(id);
	}

One-To-One Relationship

SQL

CREATE TABLE student_info(
	id VARCHAR(100) NOT NULL,
	name VARCHAR(100) NOT NULL,
	age int NOT NULL,
	class VARCHAR(100) NOT NULL,
	PRIMARY KEY (id)
)ENGINE = InnoDB;

CREATE TABLE student_address(
    id int NOT NULL,
    address VARCHAR(100) NOT NULL,
    student_id VARCHAR (100),
    PRIMARY KEY (id)
)ENGINE = InnoDB;

Modals

@Entity(name = "student_info")
@DynamicInsert
@DynamicUpdate
public class Student
{
	@Id
	@Column(name = "id")
	private String studentId;

	@Column(name = "name")
	private String studentName;

	@Column(name = "age")
	private Integer studentAge;

	@Column(name = "class")
	private String studentClass;

	@OneToOne(mappedBy = "student", cascade = CascadeType.ALL)
	private Address address;
	...
}
@Entity(name = "student_address")
public class Address {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long id;

    @Column(name = "address")
    private String address;

    @OneToOne
    @JoinColumn(name = "student_id")
    private Student student;
    ...
}

Service

	@Override
	public void insertNewStudent(String name, Integer age, 
	String studentClass, String address){
		Student student = new Student();
		Address address1 = new Address();
		String studentId = UUID.randomUUID().toString();
		address1.setAddress("MK");
		address1.setStudent(student);
		student.setStudentId(studentId);
		student.setStudentName(name);
		student.setStudentAge(age);
		student.setStudentClass(studentClass);
		student.setAddress(address1);
		studentRepository.save(student);
	}
  • Since Student is a entry point, so cascade must be added to Student class

One-To-Many Relationship

SQL

CREATE TABLE student_info(
	id VARCHAR(100) NOT NULL,
	name VARCHAR(100) NOT NULL,
	age int NOT NULL,
	class VARCHAR(100) NOT NULL,
	PRIMARY KEY (id)
)ENGINE = InnoDB;

CREATE TABLE student_hobby(
    id int NOT NULL,
    hobby VARCHAR (100) NOT NULL,
    student_id VARCHAR (100),
    PRIMARY KEY (id)
)

Modals

@Entity(name = "student_info")
@DynamicInsert
@DynamicUpdate
public class Student
{
	@Id
	@Column(name = "id")
	private String studentId;

	@Column(name = "name")
	private String studentName;

	@Column(name = "age")
	private Integer studentAge;

	@Column(name = "class")
	private String studentClass;

	@OneToMany(mappedBy = "student", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
	private List<Hobby> hobbyList;

	...
}
@Entity(name = "student_hobby")
public class Hobby {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long id;

    @Column(name = "hobby")
    private String hobby;

    @ManyToOne
    @JoinColumn(name = "student_id")
    private Student student;
    ...
}

Service

@Override
	public void insertNewStudent(String name, Integer age, String studentClass){
		Student student = new Student();
		List<Hobby> hobbyList = new ArrayList<>() ;
		hobbyList.add(new Hobby("football",student));
		hobbyList.add(new Hobby("basketball",student));
		String studentId = UUID.randomUUID().toString();
		student.setStudentId(studentId);
		student.setStudentName(name);
		student.setStudentAge(age);
		student.setStudentClass(studentClass);
		student.setHobbyList(hobbyList);
		studentRepository.save(student);
	}
  • Fetch type is divided into 2 types - lazy (default) and eager

  • Lazy: the list of hobby will not be obtained immediately when a student is obtained from database, only when the getter of student is called, the list of hobby can be obtained

  • Eager: When student is obtained from database, the list of hobby is obtained immediately, even the list will not be used

  • Fetch Mode:

  • Lazy -> SELECT(default)

  • EAGER -> JOIN(default), SUB-SELECT

Many-To-Many Relationship

SQL

CREATE TABLE student_info(
	id VARCHAR(100) NOT NULL,
	name VARCHAR(100) NOT NULL,
	age int NOT NULL,
	class VARCHAR(100) NOT NULL,
	PRIMARY KEY (id)
)ENGINE = InnoDB;

CREATE TABLE course_info(
    id VARCHAR(100) NOT NULL,
    name VARCHAR(100) NOT NULL,
    PRIMARY KEY(id)
)

CREATE TABLE student_course(
    student_id VARCHAR(100) NOT NULL,
    course_id VARCHAR(100) NOT NULL,
    PRIMARY KEY(student_id, course_id)
)

Modals

@Entity(name = "student_info")
@DynamicInsert
@DynamicUpdate
public class Student
{
	@Id
	@Column(name = "id")
	private String studentId;

	@Column(name = "name")
	private String studentName;

	@Column(name = "age")
	private Integer studentAge;

	@Column(name = "class")
	private String studentClass;

	@ManyToMany(cascade = CascadeType.ALL, mappedBy = "studentList")
	private List<Course> courseList;
	
	...
}
@Entity(name = "course_info")
public class Course {
    @Id
    @Column(name = "id")
    private String id;

    @Column(name = "name")
    private String name;

    @ManyToMany
    @JoinTable(
            name = "student_course",
            joinColumns = @JoinColumn(name = "course_id"),
            inverseJoinColumns = @JoinColumn(name = "student_id")
    )
    private List<Student> studentList;

    ...
}

Service

@Override
	public void insertNewStudent(){
		List<Student> studentList1 = new ArrayList<>();
		List<Student> studentList2 = new ArrayList<>();
		List<Student> studentList3 = new ArrayList<>();
		List<Course>  courseList1 = new ArrayList<>();
		List<Course>  courseList2 = new ArrayList<>();
		Student peter = new Student("s1","Peter",18,"6D");
		Student tom = new Student("s2","Tom",19,"6C");
		Course chinese = new Course("c1","Chinese");
		Course english = new Course("c2","English");
		Course math = new Course("c3","Math");
		studentList1.add(peter);
		studentList2.add(peter);
		studentList2.add(tom);
		studentList3.add(tom);
		courseList1.add(chinese);
		courseList1.add(english);
		courseList2.add(english);
		courseList2.add(math);
		peter.setCourseList(courseList1);
		tom.setCourseList(courseList2);
		chinese.setStudentList(studentList1);
		english.setStudentList(studentList2);
		math.setStudentList(studentList3);
		studentRepository.saveAll(studentList2);
	}

Customize Repository

Method 1

Custom Interface

public interface CustomStudentRepository {
    List<String> getStudentByClass(String className);
    Student getStudentById(String Id);
}

Custom Implementation

@Repository
public class CustomStudentRepositoryImpl implements CustomStudentRepository {

    @Autowired
    private EntityManager entityManager;

    private static final String STUDENT_TABLE = "student_info";

    @Override
    public List<String> getStudentByClass(String className){
        String sql = String.format("SELECT name FROM %s WHERE class = :className", STUDENT_TABLE);
        List<String> nameList = entityManager.createNativeQuery(sql).setParameter("className",className).getResultList();
        return nameList;
    }
    
    @Override
    public Student getStudentById(String Id){
        String sql = String.format("SELECT * FROM %s WHERE id = :Id", STUDENT_TABLE);
        Student student = (Student) entityManager.createNativeQuery(sql, Student.class).setParameter("Id", Id).getSingleResult();
        return student;
    }
}

Original Interface

@Repository
public interface StudentRepository extends JpaRepository<Student,String>, CustomStudentRepository
{
   Student getStudentByStudentName(String name);
   Page<Student> findAll(Pageable pageable);
}

Method 2

@Repository
public interface StudentRepository extends JpaRepository<Student,String>, CustomStudentRepository
{
   Student getStudentByStudentName(String name);

   Page<Student> findAll(Pageable pageable);

   @Query(value = "SELECT name FROM student_info WHERE age = :age", nativeQuery = true)
   List<String> customFindStudentByStudentAge(@Param("age") Integer age);

   @Query(value = "SELECT * FROM student_info WHERE id = :id", nativeQuery = true)
   Student customFindStudentByStudentId(@Param("id") String  id);
}

Reference

Transaction

Introduction

  • Spring creates proxies for all the classes annotated with @Transactional, either on the class or on any of the methods. The proxy allows the framework to inject transactional logic before and after the running method, mainly for starting and committing the transaction, which applies AOP on the application

Implementation

@Service
@Transactional
public class FooService {
    //...
}
  • Apart from that, we can also use programatic approach to implement by using transactional template

public void saveResult(String input, String input2) {
        TransactionTemplate txTemplate = new TransactionTemplate(txManager);
        txTemplate.execute(status -> {
            try{
                testRepository.save(input);
                testRepository.saveAll(input2);
                status.flush();
                log.info(
                    "Saved {} newRawTransactions for S3Object",
                    rawTransactions.size()
                 );
            }
            catch(Exception e){
                status.setRollbackOnly();
            }
            return null;
        });
    }

Propagation

Introduction

  • Propagation determines how transactions treats with other transaction

  • Spring calls TransactionManager::getTransaction to get or create a transaction according to the propagation.

Required

  • If a transaction is already active when the method is called, the method will run within that transaction. If a transaction is not active, a new transaction will be started.

Required_new

  • This option always starts a new transaction, regardless of whether a transaction is already active when the method is called. Any existing transaction will be suspended until the new transaction is complete.

  • If an exception is thrown and caught within the transaction, only the changes made within the current transaction will be rolled back, and the outer transaction will continue unaffected.

/**
* ProductService.java
*/
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateProductQuantityWithRequiresNewPropagation(OrderItem item) {
    // Find the product
    Product product = productRepository.findById(item.getProduct().getId())
            .orElseThrow(() -> new RuntimeException("Product not found"));

    // Update the stock quantity
    int newQuantity = product.getQuantity() - item.getQuantity();
    if (newQuantity < 0) {
        throw new RuntimeException("Insufficient stock");
    }
    product.setQuantity(newQuantity);
    productRepository.save(product);
}

/**
* SpringTransactionTest.java
* Description.    : `updateProductQuantityWithRequiresNewPropagation` was using REQUIRES_NEW propagation, 
*                   if exception happened every action inside this transaction should rollback, but the 
*                   outer transaction should continue without affected.
* Expected Result : Order record is created, product record is rollback.
*/
@Test
@Transactional
public void testUpdateProductQuantityWithRequiresNewPropagationAndInnerException() {
    // Create one order
    Order order = new Order();
    order.setCustomerName("testUpdateProductQuantityWithRequiresNewPropagationAndInnerException");
    order.setStatus(OrderStatus.PENDING);
    orderRepository.save(order);

    try {
        OrderItem item = new OrderItem();
        item.setProduct(new Product()); // Here we passed empty Product, so exception occured.
        productService.updateProductQuantityWithRequiresNewPropagation(item);
    } catch (RuntimeException e) {

    }

   // Verify that the order was created.
   Order savedOrder = orderRepository.findById(order.getId()).get();
   assertEquals(order.getCustomerName(), savedOrder.getCustomerName());
}

Mandatory

  • A transaction is already active when the method is called. If a transaction is not active, an exception will be thrown.

/**
* OrderService.java
*/
@Transactional(propagation = Propagation.MANDATORY)
public void updateOrderStatus(Long orderId, OrderStatus status) {
    Order order = orderRepository.findById(orderId)
            .orElseThrow(() -> new RuntimeException("Order not found"));
    order.setStatus(status);
    orderRepository.save(order);
}

/**
* SpringTransactionTest.java
* Description.    : `updateOrderStatus` was using MANDATORY propagation, 
*                   if the caller method doesn't initiate a transaction, 
*                   an exception will throw.
* Expected Result : IllegalTransactionStateException occured.
*/
@Test
public void testMandatoryPropagationWithoutTransaction() {
    Order order = new Order();
    order.setCustomerName("testMandatoryPropagationWithoutTransaction");
    order.setStatus(OrderStatus.PENDING);
    orderRepository.save(order);
    assertThrows(IllegalTransactionStateException.class, () -> {
            orderService.updateOrderStatus(order.getId(), OrderStatus.COMPLETED);
    });
}

Never

  • A transaction should not be active when the method is called. If a transaction is already active, an exception will be thrown.

@Transactional(propagation = Propagation.NEVER)
public void deleteOrder(Order order) {
    this.orderRepository.delete(order);
    this.orderDetailRepository.delete(order.getDetail());
}

@Test
@Transactional
public void testNeverPropagationWithTransaction() {
    assertThrows(IllegalTransactionStateException.class, () -> {
        orderService.deleteOrder(new Order());
    });
}

Not Supported

  • The method should not run within a transaction, but if a transaction is already active, it will be suspended until the method is complete

/**
* ProductService.java
*/
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void createProductWithNotSupportedPropagationWithException() {
    Product product = new Product();
    product.setName("This product created with NOT_SUPPORTED propagation and exception.");
    product.setQuantity(10);
    product.setPrice(BigDecimal.valueOf(10.0));
    productRepository.save(product);
    throw new RuntimeException("DummyException: Simulating an error");
}

/**
* SpringTransactionTest.java
* Expected Result : product was created, order was rollback.
*/
@Test(expected = RuntimeException.class)
@Transactional
public void testCreateProductWithNotSupportedPropagationWithTransactionAndException() {

    Order order = new Order();
    order.setCustomerName("testCreateProductWithNotSupportedPropagationWithTransactionAndException");
    order.setStatus(OrderStatus.PENDING);
    orderRepository.save(order);

    productService.createProductWithNotSupportedPropagationWithException();
}

/**
* SpringTransactionTest.java
* Expected Result : product was created, order was created.
*/
@Test(expected = RuntimeException.class)
public void testCreateProductWithNotSupportedPropagationWithoutTransactionAndException() {
    Order order = new Order();
    order.setCustomerName("testCreateProductWithNotSupportedPropagationWithoutTransactionAndException");
    order.setStatus(OrderStatus.PENDING);
    orderRepository.save(order);

    productService.createProductWithNotSupportedPropagationWithException();
}

Supported

  • If a transaction is already active when the method is called, the method will run within that transaction. If a transaction is not active, the method will run outside of the transaction

/**
* ProductService.java
*/
@Transactional(propagation = Propagation.SUPPORTS)
public Product createProductWithSupportsPropagationAndException() {
    Product product = new Product();
    product.setName("This product created with SUPPORTS propagation and exception.");
    product.setQuantity(10);
    product.setPrice(BigDecimal.valueOf(10.0));
    productRepository.save(product);
    throw new RuntimeException("DummyException: Simulating an error");
}

/**
* SpringTransactionTest.java
* Expected Result : product was rollback, order was rollback.
*/
@Test(expected = RuntimeException.class)
@Transactional
public void testCreateProductWithSupportPropagationWithTransactionAndException() {
    Order order = new Order();
    order.setCustomerName("testCreateProductWithSupportPropagationWithTransactionAndException");
    order.setStatus(OrderStatus.PENDING);
    orderRepository.save(order);

    productService.createProductWithSupportsPropagationAndException();
}

/**
* SpringTransactionTest.java
* Expected Result : product was created, order was created.
*/
@Test(expected = RuntimeException.class)
public void testCreateProductWithSupportPropagationWithoutTransactionAndException() {
    Order order = new Order();
    order.setCustomerName("testCreateProductWithSupportPropagationWithoutTransactionAndException");
    order.setStatus(OrderStatus.PENDING);
    orderRepository.save(order);

    productService.createProductWithSupportsPropagationAndException();
}

The transient state is the first state of an entity object. When we instantiate an object of a using the new operator then the object is in the transient state. This object is not connected with any hibernate session.

@DynamicInsert / DynamicUpdate: If the field is null, the field will not be inserted or updated , in order to improve the efficiency, detail:

POJO class
https://www.gaoyaxuan.net/blog/425.html
https://www.baeldung.com/hibernate-fetchmode
https://www.jianshu.com/p/23bd82a7b96e
LogoSpring Data JPA @Query | BaeldungBaeldung
The differences between table and java object
The format of relative table