== baseline: persist a Product whose Map holds only JSON-native Java types (String, Integer, Double, Map, List) sql> insert into product (attributes,dimensions,name,specs,tags) values (?,?,?,?,?) == load, change nothing, commit UPDATE statements: 0 == in-place mutations: load, mutate the object graph, commit, count UPDATEs attributes.put("color", "blue") -> 1 UPDATE update product set attributes=?,dimensions=?,name=?,specs=?,tags=? where id=? attributes.remove("stock") -> 1 UPDATE update product set attributes=?,dimensions=?,name=?,specs=?,tags=? where id=? ((Map) attributes.get("nested")).put("k2", 1) [nested map] -> 1 UPDATE update product set attributes=?,dimensions=?,name=?,specs=?,tags=? where id=? ((List) nested.get("k")).add(4) [list inside map] -> 1 UPDATE update product set attributes=?,dimensions=?,name=?,specs=?,tags=? where id=? tags.add("c") -> 1 UPDATE update product set attributes=?,dimensions=?,name=?,specs=?,tags=? where id=? specs.setMaterial("brass") [POJO setter] -> 1 UPDATE update product set attributes=?,dimensions=?,name=?,specs=?,tags=? where id=? specs.getCertifications().add("UL") [list inside POJO] -> 1 UPDATE update product set attributes=?,dimensions=?,name=?,specs=?,tags=? where id=? setDimensions(new Dimensions(9,9,9)) [record replaced] -> 1 UPDATE update product set attributes=?,dimensions=?,name=?,specs=?,tags=? where id=? setDimensions(equal record) [no real change] -> 0 UPDATE == the changes really reached the database attributes = {"color": "blue", "price": 19.9, "nested": {"k": [1, 2, 3, 4], "k2": 1}} tags = ["a", "b", "c"] specs = {"material": "brass", "weightKg": 1.8, "certifications": ["CE", "UL"]} == spurious UPDATEs: nothing changed, Hibernate writes anyway persist() with attributes.price = new BigDecimal("19.90") -> 1 UPDATE right after the INSERT sql> insert into product (attributes,dimensions,name,specs,tags) values (?,?,?,?,?) sql> update product set attributes=?,dimensions=?,name=?,specs=?,tags=? where id=? stored price after that persist: 19.90 then a plain load + commit of that row -> 0 UPDATE load + commit of a row whose POJO has NO equals(), nothing touched -> 1 UPDATE sql> select l1_0.id,l1_0.specs from loose l1_0 where l1_0.id=? sql> update loose set specs=? where id=? same for Specs, which HAS equals() (Product row, nothing touched) -> 0 UPDATE == @DynamicUpdate: only the changed JSON column is written sql> update dyn set a=? where id=?