In Hibernate 2, you could sort-of do a bulk delete via the
Session interface. In Hibernate 3, they have true bulk deletes, ala Section 3.11 of the EJB 3 Persistence API. However, they have some significant differences which people migrating to the new functionality need to be aware of.
The main difference is a difference in behaviour. Under Hibernate 2, the
Session.delete(String) method took a HQL query string. It then executed that query, iterated over the result, and called
Session.delete(Object) on each object. This meant that the performance was relatively slow (n+1 database calls, where n was the number of objects to delete). OTH, it also meant that the various side-effects of deleting a single object (cascades, cache updates, etc) were respected.
In Hibernate 3, the
Session.delete(String) method is deprecated; it’s no longer on the main Session interface, but it is available on the ‘classic’ interface. Instead, they now have support for DELETE queries. These get translated to a proper SQL delete query, resulting in only one database call. Much faster, BUT it doesn’t seem to respect the side-effects.
So, here’s the list of differences you want to be aware of when migrating:
The calling method has changed. Instead of
- The HQL syntax has restrictions. These are:
- You can not use aliases. So
"delete from Foo foo where foo.bar = :bar"isn’t valid, while
"delete from Foo where bar = :bar"is.
- No inner joins in the query (you _can_ use subselects in the where clause, for similar behaviour)
- And, of course, you need to have “delete” at the front.
- You can not use aliases. So
- Using a bulk delete query is not the same as deleting the objects one after another. You do _not_ get cascading deletions, so if you want them, you’d better configure your database for them instead. I’m don’t know the impact on cached objects (either in the session or the second-level cache) – test with care.
- Again: pay real care to relational constraints. For example: using a bulk delete will not delete entries from join tables, or delete dependent objects. If you need this, and you want to use the bulk update, you will need
CASCADE DELETEturned on in the database.
session.delete("from Foo"), it’s now
session.createQuery("delete from Foo").executeUpdate().
- treat DELETE queries with care; they are not a simple upgrade from the old mechanism. It is entirely different, and it has different behaviour.
- Read and understand the “relevant” sections of the EJB 3 Persistence spec.
- If in doubt, use the ‘classic’ version to preserve the behaviour. That’s certainly what I’ll be planning on doing.
There may well be more differences; I’m not finished exploring this behaviour yet, by any means, and it’s not very well documented. Most of the Hibernate documentation says “see the EJB spec”, and the EJB spec itself doesn’t elaborate on the implications very well (for example: there is no mention of the cascade behaviour, yea or nay, in Section 3.11 where the bulk deletes are defined).
As I find out more, I’ll update this posting (particularly if I find out the interaction with the caches).
(I’d also like to stress I’m _not_ trying to diss the Hibernate team; it’s a great product that I really enjoy using. But the overlap with EJB 3 is more than a little rough, guys, and this is a “Here Be Dragons” area)
 I wish I knew what these were… try Section 3.11 and 2.3.2 of the draft spec, at a minimum.
 I’m sure that Hibernate implements the intent of the spec – Gavin King, after all, helped draft the spec. But discerning that intent isn’t an easy task for mere mortals such as myself.