Hibernate – Update an Existing Record
Updating a record in Hibernate is a two-step operation: first load the entity by its primary key, then modify the fields and either let Hibernate auto-detect the change (dirty checking) or call session.merge()/session.update() explicitly. This tutorial shows both approaches with a complete working example.
Prerequisites
- Java 8 or later
- Hibernate 5.x
- MySQL database
- Maven project
Database Table
CREATE TABLE product (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(45) DEFAULT NULL,
price DECIMAL(10,0) DEFAULT NULL,
quantity INT DEFAULT NULL,
description VARCHAR(450) DEFAULT NULL,
active TINYINT(1) DEFAULT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/java9rdb</property>
<property name="connection.username">root</property>
<property name="connection.password">yourpassword</property>
<property name="dialect">org.hibernate.dialect.MySQL8Dialect</property>
<property name="show_sql">true</property>
<property name="hbm2ddl.auto">update</property>
<mapping class="com.java9r.model.Product"/>
</session-factory>
</hibernate-configuration>
Product Entity
package com.java9r.model;
import javax.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "product")
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "name", length = 45)
private String name;
@Column(name = "price")
private Long price;
@Column(name = "quantity")
private Integer quantity;
@Column(name = "description", length = 450)
private String description;
@Column(name = "active")
private Boolean active;
@Column(name = "created_at")
private LocalDateTime createdAt;
public Product() {}
// Getters
public Integer getId() { return id; }
public String getName() { return name; }
public Long getPrice() { return price; }
public Integer getQuantity() { return quantity; }
public String getDescription() { return description; }
public Boolean getActive() { return active; }
// Setters
public void setName(String name) { this.name = name; }
public void setPrice(Long price) { this.price = price; }
public void setQuantity(Integer quantity) { this.quantity = quantity; }
public void setDescription(String description) { this.description = description; }
public void setActive(Boolean active) { this.active = active; }
@Override
public String toString() {
return String.format("Product{id=%d, name='%s', price=%d, qty=%d}",
id, name, price, quantity);
}
}
HibernateUtil
package com.java9r.util;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static final SessionFactory sessionFactory =
new Configuration().configure().buildSessionFactory();
public static SessionFactory getSessionFactory() { return sessionFactory; }
public static void shutdown() { sessionFactory.close(); }
}
ProductDAO – Update Approaches
package com.java9r.dao;
import com.java9r.model.Product;
import com.java9r.util.HibernateUtil;
import org.hibernate.Session;
import org.hibernate.Transaction;
public class ProductDAO {
// ------------------------------------------------------------------
// Approach 1: Load inside the same session — dirty checking handles
// the UPDATE automatically on commit, no explicit update() call needed
// ------------------------------------------------------------------
public void updateInsideSameSession(Integer id, String newName, Long newPrice) {
Transaction tx = null;
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
tx = session.beginTransaction();
Product p = session.get(Product.class, id);
if (p == null) {
System.out.println("Product not found: " + id);
return;
}
// Just change the fields — Hibernate detects the change and issues UPDATE
p.setName(newName);
p.setPrice(newPrice);
tx.commit(); // UPDATE SQL runs here automatically
System.out.println("Updated (dirty check): " + p);
} catch (Exception e) {
if (tx != null) tx.rollback();
throw e;
}
}
// ------------------------------------------------------------------
// Approach 2: Detached entity — use session.merge() to re-attach and
// update a Product object that was loaded in a different session
// ------------------------------------------------------------------
public void updateDetachedEntity(Product detachedProduct) {
Transaction tx = null;
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
tx = session.beginTransaction();
Product merged = session.merge(detachedProduct); // re-attaches + issues UPDATE
tx.commit();
System.out.println("Updated (merge): " + merged);
} catch (Exception e) {
if (tx != null) tx.rollback();
throw e;
}
}
// ------------------------------------------------------------------
// Approach 3: HQL UPDATE — batch-update without loading the entity
// ------------------------------------------------------------------
public int updatePriceByHQL(Integer id, Long newPrice) {
Transaction tx = null;
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
tx = session.beginTransaction();
int rows = session.createQuery(
"UPDATE Product SET price = :price WHERE id = :id")
.setParameter("price", newPrice)
.setParameter("id", id)
.executeUpdate();
tx.commit();
System.out.println("Rows updated: " + rows);
return rows;
} catch (Exception e) {
if (tx != null) tx.rollback();
throw e;
}
}
// Helper: load a product (returns detached after session closes)
public Product findById(Integer id) {
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
return session.get(Product.class, id);
}
}
}
Main Class
package com.java9r;
import com.java9r.dao.ProductDAO;
import com.java9r.model.Product;
import com.java9r.util.HibernateUtil;
public class UpdateProductMain {
public static void main(String[] args) {
ProductDAO dao = new ProductDAO();
// Approach 1: update inside same session using dirty checking
dao.updateInsideSameSession(1, "Gaming Mouse", 2500L);
// Approach 2: load, detach, modify, re-attach with merge
Product p = dao.findById(2); // loaded in one session (now detached)
p.setDescription("Updated description");
p.setQuantity(100);
dao.updateDetachedEntity(p); // merged in a new session
// Approach 3: HQL bulk update
dao.updatePriceByHQL(3, 3000L);
HibernateUtil.shutdown();
}
}
Expected Output
Hibernate: select ... from product where id=?
Hibernate: update product set name=?, price=? where id=?
Updated (dirty check): Product{id=1, name='Gaming Mouse', price=2500, qty=50}
Hibernate: select ... from product where id=?
Hibernate: update product set description=?, quantity=? where id=?
Updated (merge): Product{id=2, name='Smartphone', price=25000, qty=100}
Hibernate: update product set price=? where id=?
Rows updated: 1
Choosing the Right Update Approach
| Approach | Entity State | Loads Entity First? | Best For |
|---|---|---|---|
| Dirty Checking | Persistent (managed) | Yes | Single record, UI edit flows |
session.merge() |
Detached | Yes (SQL SELECT first) | REST APIs passing DTOs back |
| HQL UPDATE | Not loaded | No | Bulk updates, performance-critical paths |
Summary
Hibernate provides three ways to update a record. The simplest is to load the entity in an open session and change its fields — Hibernate's dirty-checking mechanism detects the changes and issues the UPDATE on commit. Use session.merge() when the entity was loaded in a different session (detached state). Use HQL bulk updates when you need to update many rows without loading them into memory. Always wrap updates in a transaction and roll back on error.
Comments