Hibernate Tips: How to exclude unchanged columns from generated update statements


Take your skills to the next level!

The Persistence Hub is the place to be for every Java developer. It gives you access to all my premium video courses, monthly Java Persistence News, monthly coding problems, and regular expert sessions.


Hibernate Tips is a series of posts in which I describe a quick and easy solution for common Hibernate questions. If you have a question you like me to answer, please leave a comment below.

Question:

Hibernate always updates all database columns mapped by my entity, even the ones that I didn’t change. How can I tell Hibernate to exclude unmodified attributes from the update statement?

Solution:

Generating SQL statements takes time and Hibernate, therefore, uses one cached SQL UPDATE statement per entity. It sets all database columns so that it can be used for all update operations. You can change that with the @DynamicUpdate annotation. It tells Hibernate to generate a new SQL statement for each update operation.

You can see an example of it in the following code snippet. The only thing you need to do is to add the @DynamicUpdate annotation to your entity class.

@Entity
@DynamicUpdate
public class Book {
	
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "id", updatable = false, nullable = false)
	private Long id;

	@Version
	private int version;

	private String title;
	
	private Double price;

	...
}

When you now modify the price of the Book entity, Hibernate generates an SQL statement for this operation. As you can see in the log messages, it only changes the price and version column in the Book table.

Book b = em.find(Book.class, 1L);
b.setPrice(9.99D);
12:45:23,097 DEBUG [org.hibernate.SQL] - 
    select
        book0_.id as id1_0_0_,
        book0_.price as price2_0_0_,
        book0_.publishingDate as publishi3_0_0_,
        book0_.title as title4_0_0_,
        book0_.version as version5_0_0_ 
    from
        Book book0_ 
    where
        book0_.id=?
12:45:23,133 DEBUG [org.hibernate.SQL] - 
    update
        Book 
    set
        price=?,
        version=? 
    where
        id=? 
        and version=?

Learn More

You can also implement your own update statement with JPQL or the Criteria API. That allows you to customize the statement in any way you want. But please be aware, that Hibernate isn’t aware of the changes and doesn’t update its caches.

You can read more about custom update operations in:

Hibernate Tips Book

Get more recipes like this one in my new book Hibernate Tips: More than 70 solutions to common Hibernate problems.

It gives you more than 70 ready-to-use recipes for topics like basic and advanced mappings, logging, Java 8 support, caching, and statically and dynamically defined queries.

Get it now!

7 Comments

  1. Hibernate always updates all database columns mapped by my entity, even the ones that I didn’t change. How can I tell Hibernate to exclude unmodified attributes from the update statement?

  2. As per your topic, It is okay to update one field but if any domain contains 100 fields and in update if we don’t know which are fields going to update how can we use @dynamicUpdate?

    1. Avatar photo Thorben Janssen says:

      You don’t need to know which entity attributes you are going to update. Hibernate identifies the changed attributes during the dirty check.
      Without the @DynamicUpdate, Hibernate executes an SQL UPDATE statement that changes all database columns, if the value of at least one entity attribute changed.
      With the @DynamicUpdate, Hibernate identifies which attributes were changed and generates an SQL UPDATE statement that only includes these attributes/columns.

  3. Also, I really wish if Hibernate can update an entity without first selecting it and without using custom query. For example:

    Session session = (Session)em.unwrap(Session.class);
    Book b = session.load(Book .class, 1L);
    b.setName(“another name”);
    session.saveWithoutSelect(b);

    and then saveWithoutSelect will update the entity without first selecting it. This is easily doable and Hibernate can deduce which fields have been changed through bytecode instrumentation, but sadly there is no such API and we are forced to write a custom JPQL or HQL for such scenarios

    1. Avatar photo Thorben Janssen says:

      I don’t think I get the question. Hibernate shouldn’t perform an additional query before updating an entity.
      You first need to fetch the entity from the database so that it becomes managed. On this managed entity, you can then call your setter methods to change entity attributes. That makes the entity dirty, and Hibernate executes the update during the next flush operation. You don’t need to call any method on your Session for that and Hibernate doesn’t perform any additional query.

  4. Another great tip! Thank you Thorben. I have a question if you don’t mind: why dont’t @DynamicUpdate cache the generated query based on changed fields? In your example, if I changed the price field, Hibernate will generate an update query for this change, now if I changed the price of another entity Hibernate should just reuse the previously generated cached query instead of generating a new one. Only when I change the price AND name then Hibernate should generate a new update statement and also it should add it to its query cache so it may be used for another price and name change.

    1. Avatar photo Thorben Janssen says:

      Hi Ammar,

      That’s a good question. I can only speculate about why they don’t cache the statement. I would expect that most applications execute so many different statements that the management overhead of the cache would be higher than the performance gain.

      Regards,
      Thorben

Comments are closed.