开发者

JPA/Hibernate selective flush

I guess I'll start with

The Question

Is there a way to ensure that only entities that have been explicitly 'marked' in some way are flushed to the database?

The Environment

We are using Java EE 5, Seam 2, JBoss AS 6 and Hibernate (although we try to keep direct Hibernate dependencies minimal).

The Goal

Currently we have entities that are mapped to transient DTO objects which are then used in the business layer and bound to facelets for presentation. When we need to save data we map the DTOs back to entities and persist them. I'd like to replace the DTO with a wrapper business object that wraps an entity so that:

  • No mapping is required as the business object will call getters and setters on the wrapped entity instead of storing it's own copy of the data.
  • Upon creation of the business object hints can be specified but if something is not fetched then it can be automatically fetched later on lazily as per JPA. This is my pet peeve. I hate having to manually fetch something extra every time I need it. It often results in over-complicated 'business' code, especially when there is lots of data and it is too slow to fetch it all up-front. When I call getRelatedStuff() it should just be there.
  • Saving is as simple as 'marking' the relevant business object(s) and calling flush (I was thinking of using Sea开发者_高级运维m conversation scoped transactions with manual flushing).

The Problem

The problem with this pattern is that JPA is willing and eager to flush everything to the database during a flush. I would rather tell JPA explicitly which entities I want flushed. Any I didn't specify should not be flushed.

As a secondary question, is this pattern even a good idea?


Not a good idea. In an ORM, the way to not flush changes to the database is to not make the changes to the objects. If you need such fine-grained control of the framework as you're trying to get, then you're using it wrong. With Hibernate, your business logic should be all but oblivious of there being a database back there somewhere. You're thinking of Hibernate as a layer over an RDBMS. Instead, think of it more like a Map with near-unlimited capacity, where you can store and get objects by id. As with a Map, when you get an object out of it and make changes to the object, those changes are also reflected in the Map, and other gets on the Map will see the updated object state. Of course with Hibernate, changes have to occur in a transaction, but consider that to be a memory transaction, required because the Map is accessed concurrently by multiple threads.


Sure you can.

Just call

em.clear();

before

em.merge();

This will cause any object to be detached. Then you simply pass every object you want to merge/persist as parameters of your method. This will flush to the database only the object you want.

Be careful that, after having called em.clear(), the only persisted object will be the one merged/persisted.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜