Question

I am considering using JPA in an application in order to persist a number of objects.

The usage of the application does not seem to agree with the standard JPA approach to update on every change to the object though.

The usage of the application will be such that only a few hundred objects will be active at a time, but those will each be updated several times per second.

While the application has the objects in memory, there is no need for them to be constantly updated in the database, it would just be useless IO.

Is it possible to use JPA to load a few objects in a session and, without affecting other entity-managed objects, make changes to them in memory for a few minutes and then update the database?

It would be most helpful if there was a way to do this with some of the objects being shared between sessions.

Was it helpful?

Solution

If you want that no DB changes are made to your entities, you simply detach them from your Entity Manager.

  1. To detach an object from an entity manager during a transaction, simply use the detach method.
  2. If the entity is not managed (i.e after the transaction is closed), that the entity is anyway not managed, and you can make any changed to them without extra code.

An excerpt from the JPA 2.0 specification, on how a entity gets detached:

A detached entity results from transaction commit if a transaction-scoped container-managed entity manager is used (see section 3.3); from transaction rollback (see section 3.3.2); from detaching the entity from the persistence context; from clearing the persistence context; from closing an entity man- ager; or from serializing an entity or otherwise passing an entity by value—e.g., to a separate applica- tion tier, through a remote interface, etc.

And then when decide to make your DB changes, you simply merge the detached entity: entityManager.merge(entity);.

What I think is, that you miss some JPA background, e.g what the states of an entity are and what the operations of an entityManager are. I recomment either to search for some tutorials, or to read some chapters from the JPA spec (read Chapter 3.2 Entity Instance’s Life Cycle , about 5 pages and I guarantee you will understand a lot). Also if you want that your MERGE operations cascade, there is also a solution for that in JPA. For operations on the EntityManager & good introduction in JPA: the official tutorial.

UPDATE I will try to describe you shortly what in those tutorials is important to find.

An entity instance (i.e a persistent java object) is managed, if it associated to a Persistence Context (~ an EntityManager). If it is managed, than its changes are tracked, meaning that changing the managed entity instance will be synchronized to DB. The changes are synchronized to DB, e.g. when the transaction is finished or when you call entityManager.flush() (read the subchapter 3.2.4 Synchronization to the Database for more details).

The merge operation is actually the operation with which you both update and persist an entity instance E1. It returns a managed entity instance E2, while the passed entity E1 remains not managed.

A detached entity on the other side is not tracked by the entityManager, meaning the entityManager will not see the changes that you make, until you do not merge the entity.

Both operations (there is also a persist operation, that I did not discuss) are your way to switch the state of an entity instance managed<->detached.

Now related to your question about root&children: if nothing is configured, calling a merge() or detach() on your root, will not affect your children. But there is a cascading scheme that you can use in JPA, so that e.g calling entityManager.merge(root), will be called also on its children. Of course it is up to you to decide which operation cascade and which not.

OTHER TIPS

You can control the life expectancy of the entities by means of creating you own entity manager.

It is not clear if you are talking about a JEE or a standalone application, but in any case, you need to gain access to your entity manager factory, and obtain an entity manager out of it.

Your entity manager will be linked to a persistence context. Every time you ask for an entity, it will be placed in this persistence context. If you keep you entity manager open, then, you will hit the database only the first time you read the entity. And next times, you will get them from this cache.

If you use resource local transactions, you can control when your changes will be flushed to the database. An so, you can make changes to your context for certain amount of time, and then decide to flush it,either by committing the transaction or by calling the flush method.

You may want to read this another answer to gain more understanding of the persistence contexts and how they work.

--Edit--

There are multiple ways to gain access to your entity manager factory depending on the type of application that you are building.

If this is a standalone application you can do

EntityManagerFactory emf = Persistence.createEntityManagerFactory("unit-name");

If you are using a dependency injection framework, then you can use it to inject it automatically. If you are in a JEE application, you can get it automatically injected for you using

@PersistenceUnit(unitName="main")
private EntityManagerFactory emf;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top