Subject Re: [IBO] Transaction isolcation confusion
Author Helen Borrie
At 12:56 PM 25/08/2003 +0000, you wrote:
>Hello
>
>Either I've been completely mistaken about TIB_Transaction::Isolation
>works with a setting of tiCommitted, or there's some property I've
>not set...
>
>My app displays a list of rows within a TListView. When the user
>wants to edit a row, a dialog appears and a new transaction is
>started: tiCommitted, LockWait=false, RecVersion=true.
>
>When testing with two instances of my app, I simultaneously edit the
>same record and make changes in app 1 and then commit the changes.
>Then when I come to commit app 2 (after making no changes) it commits
>OK with no exceptions.

First misunderstanding: putting a dataset into Edit mode doesn't do
anything on the server. "Edit mode" is a client-side state. (Although if
you had PessimisticLocking set true, then putting the dataset *does* post a
dummy update to the server and therefore creates a new record version).

Misunderstanding #2: that RecVersion has any effect on the "reader's
view". It doesn't. It controls what will be treated as an update
conflict. RecVersion True is the more tolerant - it says "I don't care
whether another transaction has already posted something newer than my
"latest committed" view, I want to post my changes regardless". But that,
of course, only applies if there is something to post.

Misunderstanding #3: That calling Commit on a transaction that hasn't
posted anything somehow changes database state. It doesn't. It merely
ends the transaction.


>I had expected that when app2 committed it's changes,

You said app2 didn't do any changes. But, even if it had, it wouldn't
cause an exception in ReadCommitted, since app2 would already see app1's
changes before it posted. The only time you'll get an exception with
ReadCommitted is if app2 is in a RecVersion False transaction and tries to
*post* when another transaction has already posted (but not committed) and,
in so doing, created a new record version that is newer than the last
committed version. (Or if the other transaction deleted the row, of course
- then you get an exception of a different sort...row was not located to
update...)

> to receive an
>exception because that row had already been updated by app1. This is
>not the case, whichever of the two applications commits last, updates
>the db with their copy of the data.

Correct. With ReadCommitted, the competition is all over once one
transaction commits, because the other transaction immediately sees the new
version.


>Is this how tiCommitted works? When App1 commits changes, are these
>changes availble to App2,

Yes. But if App2 actually edited (i.e. changed something in) the older
view of data that was in its own buffer, then all of the field values from
that older view, along with App2's own changes, would be written as if they
were "new data".

>can the App2 TIB_Query tell me if the row
>has been changed elsewhere,

The changes won't appear in the client buffer until you refresh, but the
transaction knows about the latest committed version as soon as it commits.

>or do I need to refresh the row?

Refreshing the row doesn't make any difference to what the transaction can
see. Looking at it from the client side, the buffer only knows about
changes done to itself. You can change this situation by setting
BufferSynchroFlags to have the buffer synch up with the server at certain
points (one or more). It still won't help if your app already changed what
was in its buffer. If you want a more reactive response to external
changes, use DMLCaching.

If you must isolate one transaction's changes from another such that appB
won't overwrite changes done by appA, then you need to use tiConcurrency
and/or pess.locking. That's certainly the case if you have an environment
where different users are likely to be performing the SAME updates on the
same record - which happens, of course, and the developer can't control bad
work organisation.

In a situation where the two apps are updating *different* columns in the
same row, you can keep tiCommitted but write custom EditSQL such that a
call to Edit will post an update to only specified fields. But that's
quite a different case to multiple users hitting the same row with
instances of the same app, because you decide at design-time *which* fields
can be updated by which application (or mode of application).

Helen