|
View:
New views
7 Messages
—
Rating Filter:
Alert me
|
|
|
Failed insert results in invalid cache stateHere's my situation:
I'm trying to determine if it's possible to retry an insert when it fails due to PK collision. (Please don't ask why, just go with it). So i've got my own ID Generator which assigns the ID of 1 to every entity. I've also built a ExceptionHandler to deal with the collision error. In the error handler i've good logic to clone the failed insert object, without the old PK. I update the ID generator's next value to 2. Then i just re-execute the query (which assigns the new ID). I then execute my tests (JUnit methods), before each of them i delete the database contents to ensure a clean slate: 1) ID Collision insert on single executable statement w/ retry disabled - # Records in DB = 1 - Correct 2) ID Collision insert on single executable statement w/ retry enabled - # Records in DB = 2 - Correct 3) ID Collision on 4th statement after 3 successful inserts (parent, child, grandchild, great-grandchild<-Collision) w/retry disabled - # Of records in DB 0 - Correct But if i do a "find" on the ID for the parent, i get back the failed inserted object from test #2. The database still has 0 contents because the whole transaction was rolled-back. Can someone tell me why the cache has failed insert objects in it, and/or how to clear them before i attempt my retries? Any help is much appreciated, and my thanks in advance. -B |
|
|
Re: Failed insert results in invalid cache stateDefinitely a tricky thing to do. Try not cloning the object, as this will violate object identity, just set its id to null and re-execute the query.
What does your error handler do exactly? I assume you are using JPA/UnitOfWork?
James Sutherland EclipseLink, TopLink Wiki: EclipseLink, TopLink Forums: TopLink, EclipseLink Book: Java Persistence |
|
|
Re: Failed insert results in invalid cache stateHere's what I've got in my ExceptionHandler:
public Object handleException(RuntimeException exception) { if (retry && exception instanceof DatabaseException) { DatabaseException dbe = (DatabaseException) exception; if (dbe.getQuery() instanceof InsertObjectQuery) { InsertObjectQuery insert = (InsertObjectQuery) dbe.getQuery(); Object dup = insert.getObject(); if (dbe.getSession().doesObjectExist(dup)) { insert.setModifyRow(null); insert.setPrimaryKey(null); ObjectBuilder builder = insert.getDescriptor().getObjectBuilder(); ObjectCopyingPolicy policy = new ObjectCopyingPolicy(); policy.setDepth(ObjectCopyingPolicy.CASCADE_ALL_PARTS); policy.setSession(dbe.getSession()); policy.setShouldResetPrimaryKey(true); Object clone = builder.copyObject(dup, policy); //Change the next sequence value builder.assignSequenceNumber(clone, dbe.getSession()); insert.setObject(clone); try { return dbe.getSession().executeQuery(insert); } catch (Throwable t) { t.printStackTrace(); throw t; } } } } throw exception; } There really isn't any way of setting the ID to null as that would assume that I know the object's class and can cast it. My attempt here is generic to handle any type object, not just predefined ones. Everything is done via JPA xml specs with Spring's JpaTemplate to handle transaction management logic. -B
|
|
|
Re: Failed insert results in invalid cache stateThis is pretty advanced stuff, so you may want to reconsider you reasons for trying to do this in the first place. You might want to instead catch the exception in your app and retry the whole transaction, or avoid having duplicate sequence numbers in the first place (EclipseLink will never generate duplicates).
To get your exception handler to work, you can't create a copy, as it violates object identity. You need to reset the object's pk to null. You could use the descriptor to do this generically. Object value = builder.getSequenceMapping().getAttributeValue(null, session); builder.getSequenceMapping().setAttributeValueInObject(dup, value);
James Sutherland EclipseLink, TopLink Wiki: EclipseLink, TopLink Forums: TopLink, EclipseLink Book: Java Persistence |
|
|
Re: Failed insert results in invalid cache stateJames,
This is a response to a previous comment you made. I had to drop this research for projects but now i'm back on it. I wanted to follow up with something you mentioned: (EclipseLink will never generate duplicates). What type of ID generator are you referring to? And, how is the guarantee made (in a clustered environment)? I can only think of a few ways: 1) A database table manages the sequences (select from table, auto-update to next value) 2) EclipseLink validates the value does not already exist as an ID in the table prior to assigning it to the object. However this doesn't guarantee that the ID won't be assigned by another process elsewhere, inserting into the same table. 3) In the above instance, a sequence manager manages state across all instance of EclipseLink in use.
|
|
|
Re: Failed insert results in invalid cache stateJPA and EclipseLink support three types of sequencing, all three are managed by the database, so never generate duplicates. TABLE uses a sequence table in the database, database transaction prevent duplicates, IDENTITY uses IDENTITY columns in the database, SEQUENCE uses SEQUENCE objects in the database.
James Sutherland EclipseLink, TopLink Wiki: EclipseLink, TopLink Forums: TopLink, EclipseLink Book: Java Persistence |
|
|
Re: Failed insert results in invalid cache stateAh! I thought you meant that EclipseLink had its own mechanism for preventing duplicates. We have been precluded from using any of the implementation items you have mentioned.
Thanks for your help! -B
|
| Free embeddable forum powered by Nabble | Forum Help |