Re: Optimistic locking failure on insert
Re: Optimistic locking failure on insert
- Subject: Re: Optimistic locking failure on insert
- From: Chuck Hill <email@hidden>
- Date: Wed, 15 Mar 2006 13:01:43 -0800
Hi,
On Mar 15, 2006, at 12:27 PM, Jerry W. Walker wrote:
On Mar 15, 2006, at 12:41 PM, Chuck Hill wrote:
On Mar 15, 2006, at 7:31 AM, Jerry W. Walker wrote:
I can't imagine (short of a bug in the development environment)
how the code you're exposing below could cause an optimistic
locking failure. The upshot of the code below only reads from the
store. It neither creates nor updates any records therein.
Optimistic locking failures occur on an attempt to write a record
to the database when the record on the database into which you're
trying to write has data other than what you expected to be
there. This is typically caused by someone else writing into the
same record before you, but can also be caused by rounding errors
in fields your checking for the optimistic locking check (e.g.
including Doubles or Date fields among the optimistic lock check
fields).
Hold on a second here. Ian is using JavaClient and that
complicates this a bit. As the clients are disconnected from the
EOF stack, they don't get notifications of "objects changed in
store" such as are broadcast in the WebObjects application
proper. So it is also possible that an optimistic locking
exception could occur when Client A's request gets to the server
and Client B has updated that object since it was sent out to
Client A.
Agreed that this is JavaClient, but I'm not sure how that
invalidates anything stated before. It simply allows the "someone
else" I mentioned to exist within the same application without
intentionally creating a new EO Stack.
Please see below.
EOF would (should) see that Client A's snapshot does not match the
snapshot in the object store and produce this exception. This is
what the message seems to be suggesting:
The object with global ID <EOTemporaryGlobalID: 0 0 -64 -88 0 7
0 0 -15 83 1 0 0 0 1 9 -9 81 65 -102 58 -107 -26 -116> has been
changed by another client
Now, that does not explain how this is happening on a newly
inserted object. Hence, I will resort to wild speculation. ;-)
1) A snapshot for the object has been registered on the server
under this temporary ID prior to this save and some server side
code has changed some value and this change was not seen by the
client. awakeFromInsertion? When the save happens the snapshot
does not match what the client has
2) Somehow duplicate EOTemporaryGlobalID's are getting generated.
This seems too implausible to even consider.
On Mar 14, 2006, at 11:54 PM, Ian Joyner wrote:
OK, found the problem. It was not in the model, but rather in
the code for initializing a JTree. First, I was getting top-
level nodes by getting them out of the display group:
NSArray notes = EOQualifier.filteredArrayWithQualifier
(display_group.allObjects (),
EOQualifier.qualifierWithQualifierFormat ("parent_note = null",
null));
however, sometimes the display group had not fetched yet, so I
used a fetch spec to go straight to the DB:
NSArray notes = editing_context.objectsWithFetchSpecification
(new EOFetchSpecification ("Note", new EOAndQualifier (new
NSArray (new Object [] {EOQualifier.qualifierWithQualifierFormat
("parent_note = null", null),
EOQualifier.qualifierWithQualifierFormat ("owner = %@", new
NSArray (new Object [] {owning_display_group.selectedObject
()}))})), null));
Is there more than one editing context in play here? Is it
possible that you have somehow got the same new object registered
in _two_ editing contexts?
The above statement is more difficult to read than it needs to
be. You can use "AND" directly in the
qualifierWithQualifierFormat method.
For some reason, which I'd like an explanation for, this caused
the optimistic locking problem when creating a new master
record. So then I realised the most straight forward solution
was to traverse the object path:
NSArray notes = EOQualifier.filteredArrayWithQualifier
(((Artifact)owning_display_group.selectedObject ()).notes (),
EOQualifier.qualifierWithQualifierFormat ("parent_note = null",
null));
That does sort of sound like a crossed editing context problem. I
don't see where the new object is coming into play though.
Is editing_context == owning_display_group.selectedObject
().editingContext()?
(The fetch spec code probably would have been better in Haskell,
but I dislike assigning things to temporary variables in Java
when the code could be more functional.)
I generally find that temporary variables can add greatly to the
semantic value of the code. It can make the code significantly
more readable. How does leaving them out make the code more
functional?
Perhaps more functional is a British term for less readable? :-P
As a "write seldom, read often" artifact, I value readability over
almost everything else.
Don't know if this little note may help anyone in the future,
because I still don't know the link between the fetch spec and
the optimistic locking failure (and I hate the hacking until it
happens to work approach).
In looking over the debugging statements below, it looks like
there is an attempt to save a member record which contains itself
as a member.
Good catch Jerry!
That is, it looks like the inserted record has the following
recursive structure:
MemberRecord:
details = null
begin_date = 3/14/2006 @ 5:53:51 GMT
position = null
member = <self reference> ************ IS THIS
CORRECT? ****************
end_date = null
group = Groups: {
<some not-yet-saved GroupMember>
}
person = null
title = <reference to previously saved title with PK = 1>
telephones = ()
modification_date = 3/14/2006 @ 5:53:51 GMT
I can certainly imagine problems with such a structure, if I'm
inferring correctly.
I don't see how exactly it would cause the exception, but it
certainly looks suspicious.
I'm guessing here, since I've never tried to create and then
persist an object graph that recurses onto itself, but might it
attempt to write the record as it first puts the inserted record
into the database, then try to update that same record as it
recurses across the relationship, identifying the record as changed
from what it assumed would be there?
But... this is not yet getting near the point where changes will be
written to the database. I do agree that the self reference may be
triggering this bug.
Have you turned on EOAdaptorDebuggingEnabled to check the
generated SQL? It looks like EOF may be attempting to write a
record that contains itself recursively and determines on the
second recursion that the record has already been written. That
would be my guess without seeing the SQL.
Ian said, "No SQL commands are being executed in the SQL trace.".
It is not getting that far.
Yeah, I'm not sure I understand that either, since it seems to me
that an optimistic locking failure could not have occurred until
the attempt was made to insert/update the record on the database.
My understanding is that the optimistic locking failure occurs when
the SQL "WHERE" clause fails to match the record in the database.
The SQL would have had to have been generated (and executed) for
that to occur.
Am I missing something here?
I think so. The exception that Ian posted is not the
EOGeneralAdaptorException that you are thinking of. It is thrown by
EODistributionContext. EODistributionContext is not an editing
context. "EODistributionContext objects perform the server-side
related work behind Java Client applications and take care of
encoding and decoding enterprise objects and other data. ...
EODistributionContext objects track the state of the server side
object graph and communicate changes to the client, thus keeping the
client and server object graphs in sync." It appears to me that what
is happening is that when the update arrives at the server, the
EODistributionContext somehow decides (erroneously, it would seem)
that it is based on an out of date snapshot. Once once it passes the
EODistributionContext would it get to an edting context, EOF stack,
and the database. All of this based on my rather limited
understanding of the JavaClient architecture.
Chuck
On 14/03/2006, at 5:09 PM, Ian Joyner wrote:
I have been running this model for six months and saving this
entity just fine. Suddenly, I am getting an optimistic locking
failure when doing an insert of a new record (that's right
insert, not update). In fact is the trace below, I show that
the offending record is in the editing contexts insertedObjects
and it has a EOTemporaryGlobalID which means it has not been
written to the database yet.
No SQL commands are being executed in the SQL trace. I have
turned off locking on every attribute for this entity in
EOModeler. Other entities are still saving fine. So what's
going on? How can I get around this problem?
[2006-03-14 16:53:56 EST] <AWT-EventQueue-0>
xxx.client.Member_interface_controller save inserted ({values =
{details = <com.webobjects.foundation.NSKeyValueCoding$Null>;
begin_date = 2006-03-14 05:53:51 Etc/GMT; position =
<com.webobjects.foundation.NSKeyValueCoding$Null>; member =
"<com.sportstec.member.client.Member f1156e
<EOTemporaryGlobalID: 0 0 -64 -88 0 7 0 0 -15 83 1 0 0 0 1 9 -9
81 65 -102 58 -107 -26 -116>>"; end_date =
<com.webobjects.foundation.NSKeyValueCoding$Null>; group =
"<com.sportstec.group.client.Group 47545b groups =
("<com.sportstec.group.client.Group_Member 8dacbb
<EOTemporaryGlobalID: 0 0 -64 -88 0 7 0 0 -15 83 2 0 0 0 1 9 -9
81 65 -102 58 -107 -26 -116>>"); person = "null"; title =
"<com.webobjects.eocontrol.EOGenericRecord dd1d62
_EOIntegralKeyGlobalID[Title (java.lang.Integer)1]>";
telephones = (); modification_date = 2006-03-14 05:53:51 Etc/
GMT; }; this = "<com.sportstec.member.client.Member f1156e
<EOTemporaryGlobalID: 0 0 -64 -88 0 7 0 0 -15 83 1 0 0 0 1 9 -9
81 65 -102 58 -107 -26 -116>>"; })
[2006-03-14 16:53:56 EST] <AWT-EventQueue-0>
xxx.client.Member_interface_controller save updated (Gq)
[2006-03-14 16:53:56 EST] <AWT-EventQueue-0>
xxx.client.Member_interface_controller save deleted ()
[2006-03-14 16:53:56 EST] <AWT-EventQueue-0>
xxx.client.Member_interface_controller EditingContext
saveChanges failed Server exception: Optimistic locking
failure: The object with global ID <EOTemporaryGlobalID: 0 0
-64 -88 0 7 0 0 -15 83 1 0 0 0 1 9 -9 81 65 -102 58 -107 -26
-116> has been changed by another client
Thanks
Ian Joyner
Sportstec
--
__ Jerry W. Walker,
WebObjects Developer/Instructor for High Performance Industrial
Strength Internet Enabled Systems
email@hidden
203 278-4085 office
--
Coming in 2006 - an introduction to web applications using WebObjects
and Xcode http://www.global-village.net/wointro
Practical WebObjects - for developers who want to increase their
overall knowledge of WebObjects or who are trying to solve specific
problems. http://www.global-village.net/products/practical_webobjects
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden