Hibernate @DynamicUpdate Example

We can update an entity only if some field value has changed by using the @DynamicUpdate annotation provided by Hibernate. This annotation tells Hibernate to generate SQL updates only for the changed fields, reducing unnecessary database operations. In this post, we are going to explore the Hibernate @DynamicUpdate Example.

The primary purpose of the @DynamicUpdate annotation is to optimize the update operation for an entity. When this annotation is applied to an entity class, Hibernate generates an SQL update statement that only includes the columns whose values have been modified in the entity, rather than updating all columns. This can lead to more efficient database updates, reducing unnecessary work in the database. Let’s see how to use JPA @DynamicUpdate annotation.

Note – Hibernate @DynamicUpdate annotation is used with class, not with method.

@Entity
@DynamicUpdate
public class Student implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

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

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

    @Column(name = "university")
    private String university;
    //getter & setter
}

Consider we want to update only one filed name. Let’s see how the hibernate query gets generated when we use Hibernate @DynamicUpdate annotation and when we don’t use Hibernate annotation. We want to update the student entity using the Spring Data JPA save() method. Consider we have a StudentRepository interface.

@Repository
public interface StudentRepository extends JpaRepository<Student, Long> {

}

StudentServiceImpl.java

@Service
public class StudentServiceImpl implements StudentService {

    @Autowired
    private StudentRepository studentRepository;

    @Transactional
    public Student update(Student student) {
        Student updateResponse = studentRepository.save(student);
        return updateResponse;
    }
}

Query generated without using Hibernate @DynamicUpdate and with using @DynamicUpdate while updating name field only

Let’s see what query hibernate generates when we update only name fields in both cases i.e without using @DynamicUpdate annotation and with using @DynamicUpdate annotation.

Without using Hibernate @DynamicUpdate

Hibernate: 
    update
        student 
    set
        name=?,
        roll_number=?,
        university=? 
    where
        id=?

Using Hibernate @DynamicUpdate

Hibernate: 
    update
        student 
    set
        name=? 
    where
        id=?

As we can see hibernate is only generating an update query for the name field if we use @DynamicUpdate annotation. This is the big advantage of using Hibernate @DynamicUpdate annotation.

Hibernate @DynamicUpdate Example using Spring Boot

Let’s see a complete example from scratch.

Create a maven project and update 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>springdatajpa</groupId>
    <artifactId>springdatajpa</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
    </parent>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
    </dependencies>

</project>

Define entity – Student.java

package com.springboot.entity;

import org.hibernate.annotations.DynamicUpdate;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
@DynamicUpdate
public class Student implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

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

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

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

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getRollNumber() {
        return rollNumber;
    }

    public void setRollNumber(String rollNumber) {
        this.rollNumber = rollNumber;
    }

    public String getUniversity() {
        return university;
    }

    public void setUniversity(String university) {
        this.university = university;
    }
}

Define StudentService.java

package com.springboot.service;

import com.springboot.entity.Student;


public interface StudentService {

    public Student save(Student student);

    public Student update(Student student);

/*
    public Student get(Long id);

    public List<Student> getStudents(String name);

    //public List<Student> getStudents();

    public void delete(Student student);
*/

}

Define Repository interface

package com.springboot.repository;

import com.springboot.entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface StudentRepository extends JpaRepository<Student, Long> {

}

Define StudentServiceImpl.java

package com.springboot.serviceimpl;

import com.springboot.entity.Student;
import com.springboot.repository.StudentRepository;
import com.springboot.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Service
public class StudentServiceImpl implements StudentService {

    @Autowired
    private StudentRepository studentRepository;


    @Transactional
    public Student save(Student student) {
        Student createResponse = null;
        createResponse = studentRepository.save(student);
        return createResponse;
    }

    @Transactional
    public Student update(Student student) {
        Student updateResponse = studentRepository.save(student);
        return updateResponse;
    }
/*

    @Transactional
    public Student get(Long id) {
        Optional<Student> response = studentRepository.findById(id);
        Student getResponse = response.get();
        return getResponse;
    }

    @Transactional
    public List<Student> getStudents(String name) {
        List<String> names = new ArrayList<>();
        names.add(name);

        List<Student> response = new ArrayList<>();
        //response = studentRepository.findDistinctByNameNotIn(names);
        return response;
    }

    @Transactional
    public void delete(Student student) {
        //studentRepository.delete(student);
    }
*/

}

Define controller class

package com.springboot.controller;

import com.springboot.config.MainConfigFiles;
import com.springboot.entity.Student;
import com.springboot.repository.StudentRepository;
import com.springboot.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/student")
public class StudentController {

    @Autowired
    private MainConfigFiles mainConfigFiles;

    @Autowired
    private StudentService studentService;

    @Autowired
    private StudentRepository studentRepository;

    @PostMapping("/create")
    public Student createStudent1(@RequestBody Student student) {

        //System.out.println(mainConfigFiles.getMessage2());
        Student createResponse = studentService.save(student);
        return createResponse;
    }

    @PutMapping("/update")
    public Student updateStudent(@RequestBody Student student) {
        Student updateResponse = studentService.update(student);
        return updateResponse;
    }

/*	@GetMapping("/{id}")
	public Student getStudent(@PathVariable Long id) {
		Student getReponse = studentService.get(id);
		return getReponse;
	}*/

/*	@GetMapping("/{name}")
	public List<Student> getStudent(@PathVariable String name) {
		List<Student> getReponse = studentService.getStudents(name);
		return getReponse;
	}*/

    /*	@GetMapping("/{students}")
        public List<Student> getStudent() {
            List<Student> getReponse = studentService.getStudents();
            return getReponse;
        }*/
/*    @DeleteMapping("/delete")
    public String deleteStudent(@RequestBody Student student) {
        studentService.delete(student);
        return "Record deleted succesfully";
    }

    @GetMapping("/getcustomfieldsbasisofuserinput")
    public String deleteStudent(@RequestParam String fields) {
        System.out.println(fields);
        //studentService.delete(student);
        return "Record deleted succesfully";
    }

    @GetMapping("/{name}")
    public List<Student> finddistinctbyname(@PathVariable String name) {
        List<Student> students = studentService.getStudents(name);
        return students;
    }*/

}

Define config class

package com.springboot.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@Configuration
@EnableJpaRepositories(basePackages = "com.springboot.repository")
public class MainConfigFiles {

    /*    @Value("${welcome.message}")
        private String message2;

        private MainConfigFiles mainConfigFiles;

        @Bean
        public MainConfigFiles jpaConfig(){

            mainConfigFiles = new MainConfigFiles();
            mainConfigFiles.setMessage2(message2);
            return mainConfigFiles;
        }

        public String getMessage2() {
            return message2;
        }

        public void setMessage2(String message2) {
            this.message2 = message2;
        }*/
}

Define main class

package com.springboot.main;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan(basePackages = "com.springboot.*")
@EntityScan("com.springboot.*")
public class SpringMain {
    public static void main(String[] args) {
        SpringApplication.run(SpringMain.class, args);
    }
}

Testing using postman

Request Data for create

{
    "name": "rakesh",
    "rollNumber": "0126CS071",
    "university": "rgtu"
}

Request Data for update

{
    "id": 1,
    "name": "rakesh",
    "rollNumber": "0126CS071",
    "university": "rgtu"
}
Hibernate @DynamicUpdate Example

Let’s see a few points about Hibernate @DynamicUpdate Example.

The @DynamicUpdate annotation is typically used in Java Persistence API (JPA) frameworks like Hibernate to control the update behavior of entities. Here are five key points about the @DynamicUpdate annotation:

  1. Selective Update Optimization:
    The primary purpose of the @DynamicUpdate annotation is to optimize the update operation for an entity. When this annotation is applied to an entity class, Hibernate generates an SQL update statement that only includes the columns whose values have been modified in the entity, rather than updating all columns.
  2. Reduced Database Load:
    By updating only the changed columns, the @DynamicUpdate annotation can reduce the load on the database server during update operations. This can be particularly beneficial in scenarios where frequent updates occur, as it minimizes the amount of data transferred between the application and the database.
  3. Example Usage:
    To use the @DynamicUpdate annotation, we typically annotate your entity class with @Entity and then add @DynamicUpdate above the class declaration. Here’s an example:
   import org.hibernate.annotations.DynamicUpdate;

   @Entity
   @DynamicUpdate
   public class Product {
       // Entity fields and methods
   }
  1. Considerations:
    While @DynamicUpdate can be beneficial for optimizing update operations, it may not be suitable for all scenarios. It is important to evaluate whether the benefits of reduced database load and improved update efficiency outweigh any potential drawbacks. Additionally, be aware that this annotation may not work as expected in all JPA implementations and may have limitations in some cases.

In summary, the @DynamicUpdate annotation in JPA is a useful tool for optimizing update operations in Hibernate and similar JPA implementations. It allows you to reduce database load and improve performance by updating only the changed columns in an entity, offering fine-grained control over the update behavior. However, it should be used judiciously and tested thoroughly to ensure it meets the requirements of your specific application.

Question 1: What is the primary purpose of the Hibernate @DynamicUpdate annotation?

A. To enable automatic table creation
B. To optimize update operations
C. To define primary keys
D. To create a new entity class

Question 2: How does the @DynamicUpdate annotation affect the update behavior of Hibernate entities?

A. It inserts new records in the database.
B. It updates all columns in the entity.
C. It generates SQL update statements for modified columns only.
D. It enforces unique constraints on entity fields.

Question 3: Can you apply the @DynamicUpdate annotation to specific entity classes, or does it affect all entities in a Hibernate application?

A. It affects all entities in the application.
B. It can only be applied to abstract classes.
C. You can apply it selectively to specific entity classes.
D. It applies only to entity fields, not entire classes.

Question 4: What are some potential benefits of using the @DynamicUpdate annotation in Hibernate?

A. Increased database load during update operations.
B. Improved database update performance.
C. Automatic generation of primary keys.
D. Fine-grained control over table creation.

Question 5: Are there any considerations or limitations when using the @DynamicUpdate annotation in Hibernate?

A. It works seamlessly with all JPA implementations.
B. Careful evaluation is needed to determine if the benefits outweigh potential drawbacks.
C. It must be used with the @Entity annotation.
D. It can only be applied to non-relational databases.

Now, here are the correct answers:

Answer 1: B. To optimize update operations

Answer 2: C. It generates SQL update statements for modified columns only.

Answer 3: C. You can apply it selectively to specific entity classes.

Answer 4: B. Improved database update performance.

Answer 5: B. Careful evaluation is needed to determine if the benefits outweigh potential drawbacks.

Hibernate @DynamicUpdate docs.

That’s all about Hibernate @DynamicUpdate Example

Other JPA Examples.