"Optimistic locking" means that you assume a record is going to be available and code to handle the exceptions. You are also optimistically anticipating that nobody else is modifying the record -- or that any such modifications are not relevant to your usage. On the surface this seems like an awful idea. But in reality it is true that most of the time it doesn't matter if someone else changes something. Plus read operations are much, much more common than updates so the odds are very much on your side.
"Pessimistic locking" means that you assume it is not available and that your code is surprised to find it is
In an optimistic locking world you generally use NO-LOCK for almost all data access that is not updating a record. So you write a lot of:
Code:
find customer no-lock where customer.custId = someId no-error.
if available( customer ) then
do:
message "no such customer!".
return.
end.
/* assume that the customer is available and carry on with whatever... */
The error is this case is not a locking error -- you are simply noticing that there was no customer with that id. This snippet of code will not block anyone else from accessing or updating the record. There can be as many NO-LOCK readers of the record as you would like. This is the method that gives you the greatest concurrency and performance.
(Also: there is no need for nor any benefit to slapping FIRST on every FIND -- it is a stupid habit taken from some very bad and quite ancient code in certain well known applications that everyone really should know better than to copy.)
To update code you should *always* use a named buffer and a strong scoped FOR block. Like this:
Code:
define buffer updCustomer for customer.
do for updCustomer transaction:
find updCustomer exclusive-lock where custId = someId no-wait no-error.
if available( customer ) then
do:
discount = 0.10. /* or whatever it is we wanted to update... */
end.
else
do:
/* don't prompt the user! you are in a transaction -- if the user goes to get a cup of coffee and then leaves for the day your bi file could grow a few terabytes... */
end.
end.
If you compile your code and you get warnings and errors about transactions already existing or being unable to reference buffers the problem is NOT with the "do for updCustomer transaction". The problem is that you have been sloppy outside of that block and you need to fix the sloppiness.
Code in this manner and you will not have problems with lock conflicts or transaction scope.
Code without specifying lock types and without controlling transaction scope and you will have a mess on your hands.