Inserts and Caching

View: New views
8 Messages — Rating Filter:   Alert me  

Inserts and Caching

by ossaert :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

I have the following design problem. I have in EJB a remote interface which actually is a projection of my use-case. This remote method calls different local apis.

Important to know is that the use-case is a unit. Or the method is committed or rolled back completely.

Now, during the execution of this method I have a call to a method which insert event-objects into the database. Unfortunately, these event objects remain in memory until my transaction commits. Is there a way to avoid this (without having to use the SQL INSERT statement directly)? I found in EclipseLink the method InsertObjectQuery.

public void sendEvent(NodeEntity nodeEntity, EventType eventType) {

        EventEntity event = new EventEntity();
        event.setNodeGuid(.....);
        event.setEventType(....);

        /* This is the EclipseLink specific part */        
        InsertObjectQuery writeQuery = new InsertObjectQuery();
        writeQuery.setObject(event);
        writeQuery.dontMaintainCache();

        /* Convert the query to JPA query */
        Query q = JpaHelper.createQuery(writeQuery, this.getEntityManager());
        q.executeUpdate();
}

This method, I hope, should be able NOT TO CACHE the EventEntity? So, when I have let's say 5000 eventEntities in my method, they will not remain in memory and will not cause a heap space problem?

Unfortunately, this method does not function within JPA (Glassfish). I get the following error:
Objects cannot be written during a UnitOfWork, they must be registered.

I tried to register it (using entitymanager.getUnitOfWork().registerNewObject() etc), but without success.

Are my assumptions correct and/or is there a method to do insert using the API in JPA (so I can refactor it easily) ? Now, as a work-around I use the SQL INSERT statement directly, but that is not always portable.

Actually, I would be nice if you could remove one object from the cache or to prevent the object from being cached. Sometimes, you have objects you must write to the database use JPA (annotated with @PrePersist etc) which you don't need afterwards.

Does the annotations @Cache(type=CacheType.NONE) actually function when I execute the normal "entitymanager.persist(eventEntity)"?

Greetings
Jan

Re: Inserts and Caching

by ossaert :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Anyone?

Thanks
Jan

Re: Inserts and Caching

by James Sutherland :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Are you concerned with caching across transaction or within the same transaction?

Across transaction you can disable caching using the persistence.xml property,
"eclipselink.cache.shared.default"="false".  Or you can set the size or type of the cache to control how many objects are cached.

For avoiding caching within a single transaction, the best way is to flush() then clear() the EntityManager.  You could do this for each object, or probably better for each batch of objects.

Also ensure you application does not hold onto the objects, otherwise they will not be able to gc.


ossaert wrote:
Hi,

I have the following design problem. I have in EJB a remote interface which actually is a projection of my use-case. This remote method calls different local apis.

Important to know is that the use-case is a unit. Or the method is committed or rolled back completely.

Now, during the execution of this method I have a call to a method which insert event-objects into the database. Unfortunately, these event objects remain in memory until my transaction commits. Is there a way to avoid this (without having to use the SQL INSERT statement directly)? I found in EclipseLink the method InsertObjectQuery.

public void sendEvent(NodeEntity nodeEntity, EventType eventType) {

        EventEntity event = new EventEntity();
        event.setNodeGuid(.....);
        event.setEventType(....);

        /* This is the EclipseLink specific part */        
        InsertObjectQuery writeQuery = new InsertObjectQuery();
        writeQuery.setObject(event);
        writeQuery.dontMaintainCache();

        /* Convert the query to JPA query */
        Query q = JpaHelper.createQuery(writeQuery, this.getEntityManager());
        q.executeUpdate();
}

This method, I hope, should be able NOT TO CACHE the EventEntity? So, when I have let's say 5000 eventEntities in my method, they will not remain in memory and will not cause a heap space problem?

Unfortunately, this method does not function within JPA (Glassfish). I get the following error:
Objects cannot be written during a UnitOfWork, they must be registered.

I tried to register it (using entitymanager.getUnitOfWork().registerNewObject() etc), but without success.

Are my assumptions correct and/or is there a method to do insert using the API in JPA (so I can refactor it easily) ? Now, as a work-around I use the SQL INSERT statement directly, but that is not always portable.

Actually, I would be nice if you could remove one object from the cache or to prevent the object from being cached. Sometimes, you have objects you must write to the database use JPA (annotated with @PrePersist etc) which you don't need afterwards.

Does the annotations @Cache(type=CacheType.NONE) actually function when I execute the normal "entitymanager.persist(eventEntity)"?

Greetings
Jan

Re: Inserts and Caching

by ossaert :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Thanks for the follow-up.

James Sutherland wrote:
Are you concerned with caching across transaction or within the same transaction?
It is the caching within the same transaction. Let's say in one transaction I have to persist 5000 objects which I do not need afterwards. They should not unnecessary remain in memory. When a couple of requests are running, then the memory is filled up pretty quickly.

Does the @Cache NONE actually helps? I wasn't able to find out if the object was cached.

James Sutherland wrote:
Across transaction you can disable caching using the persistence.xml property,
"eclipselink.cache.shared.default"="false".  Or you can set the size or type of the cache to control how many objects are cached.
Thanks for the tip.

James Sutherland wrote:
For avoiding caching within a single transaction, the best way is to flush() then clear() the EntityManager.  You could do this for each object, or probably better for each batch of objects.
Ok, but then the transaction is committed and restarted. In case of a rollback I have "unstable" data since the part before the flush wasn't rolled back.

Thanks
Jan

Re: Inserts and Caching

by James Sutherland :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

> Does the @Cache NONE actually helps? I wasn't able to find out if the object was cached.

No do not use NONE, to disable the shared cache use shared=false.  NONE should generally only be used for simple objects without relationships.

> Ok, but then the transaction is committed and restarted. In case of a rollback I have "unstable" data since the part before the flush wasn't rolled back.

No flush() does not commit the transaction, only commit() commits the transaction, flush() just writes the SQL to the database, rollback will still rollback everything from the point of the begin().


ossaert wrote:
Thanks for the follow-up.

James Sutherland wrote:
Are you concerned with caching across transaction or within the same transaction?
It is the caching within the same transaction. Let's say in one transaction I have to persist 5000 objects which I do not need afterwards. They should not unnecessary remain in memory. When a couple of requests are running, then the memory is filled up pretty quickly.

Does the @Cache NONE actually helps? I wasn't able to find out if the object was cached.

James Sutherland wrote:
Across transaction you can disable caching using the persistence.xml property,
"eclipselink.cache.shared.default"="false".  Or you can set the size or type of the cache to control how many objects are cached.
Thanks for the tip.

James Sutherland wrote:
For avoiding caching within a single transaction, the best way is to flush() then clear() the EntityManager.  You could do this for each object, or probably better for each batch of objects.
Ok, but then the transaction is committed and restarted. In case of a rollback I have "unstable" data since the part before the flush wasn't rolled back.

Thanks
Jan

Re: Inserts and Caching

by ossaert :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


James Sutherland wrote:
No flush() does not commit the transaction, only commit() commits the transaction, flush() just writes the SQL to the database, rollback will still rollback everything from the point of the begin().
Ok, but does a flush clear the cache? I.e. will the object up to this point be garbage collected?

Thanks
Jan

Re: Inserts and Caching

by ossaert :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Anyway, I still have the problem why the Insert over the API does not work....

Can somebody help?

Thanks
Jan


Re: Inserts and Caching

by Gordon Yorke-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Jan,
   Assuming that these operations occur within a single JTA or
application managed transaction you should use the following pattern.

->begin operations - transaction alpha active<-
    //operate on em
    while (?){
      em.persist(); // or whatever else needs to happen
    }
    //operation complete
   em.flush(); // flush changes to database within current transaction
   em.clear(); //clear the em (including em cache) of all managed
entities (you may not always need this)
->end operation - transaction alpha still active <-

as long as the same transaction is active for all of the operations if
anything fails a rollback of the transaction will revert all of the SQL
EclipseLink sent to the database within that transaction from all of the
previous flush operations.  On rollback the EntityManager will be
cleared and your application will have a clean slate.  The old entities
that were previously associated with this EM will now be detached and
are in a state where they may have uncommitted changes.  Some
applications can use these detached instances to retry the transaction
with EM.merge() other applications will throw them away and start from
scratch.

--Gordon

ossaert wrote:

> Anyway, I still have the problem why the Insert over the API does not
> work....
>
> Can somebody help?
>
> Thanks
> Jan
>
>
>  
_______________________________________________
eclipselink-users mailing list
eclipselink-users@...
https://dev.eclipse.org/mailman/listinfo/eclipselink-users