MS Access Forum / Multiuser / Networking / November 2005
Record Locking Schemes?
|
|
Thread rating:  |
kiln - 24 Nov 2005 21:50 GMT I've read around here and there about record locking and have come up with kind of an incomplete mixed bag of results. A particular app I'm working on is more prone to concurrent record editing contention than most I've done. Here are some bits of info an experience that I'd be glad to hear comments on. This is jet all the way, as secured as Access can be, Access 2000 soon-to-be Access 2003, with the regular FE BE split format, each workstation running it's own copy of the db FE.
I've read that recordset .EditMode is kind of useless and have not been able to get it to return a value other than 0...but that was early on in my testing and maybe I missed something.
Probably optimistic locking is not the best for this app. If one user has started to edit a record, I want any other user that starts to edit the rec to be warned and prevented from continuing.
I'm intersted in hearing aobut whatever works for any reader, but what seems to be regarded as the best route for preventing concurrent edits is to set the form to Record Locks = Edited Record, aka pessimistic locking, and then use a recordset to try to edit that rec; if .edit produces an error, bail out of the second users edit attempt (probably in the On Dirty event of the form?) But what I don't understand is that even with tiny data populations and FE aned BE on the same pc, it takes at least a second for the routine to cough up the msg that the rec can't be edited and then back out the changes. How can it take so long? I'll test more but in the meantime here is the test code (IsRecordsetLocked() was more or less blindly copied from a post here):
Private Sub Form_Dirty(Cancel As Integer) Dim db As Database Dim rs As Recordset Dim strSQL As String Dim boolLocked As Boolean Dim strMsg As String Set db = CurrentDb strSQL = "Select qryPerson.* FROM qryPerson WHERE qryPerson.PID = " & PID Set rs = db.OpenRecordset(strSQL, dbOpenDynaset) boolLocked = IsRecordsetLocked(rs, strMsg) MsgBox "IsRecordsetLocked " & boolLocked If boolLocked = True Then Cancel = True End If End Sub
Function IsRecordsetLocked(rst As Recordset, strErrMsg As String) As Boolean ' Checks the current record in 'rst' and retuns True if it (or the ' page its in) is locked by another user or another process on ' the same machine, otherwise False.
On Error GoTo err_IsRecordsetLocked
Const cnsLockPageSave = 3186 Const cnsLockPageRead = 3187 Const cnsLockLocalUpd = 3188 Const cnsLockExclusive = 3189 Const cnsLockRecSave = 3202 Const cnsLockRecUpd = 3218 Const cnsLockPageUpd = 3260
IsRecordsetLocked = False strErrMsg = "" ' Try to edit the current record in the recordset. rst.Edit ' If we get here, No locks apply so return False. rst.CancelUpdate
exit_IsRecordsetLocked: Exit Function
err_IsRecordsetLocked: Select Case Err.Number Case cnsLockPageSave, cnsLockPageRead, cnsLockLocalUpd, _ cnsLockExclusive, cnsLockRecSave, cnsLockRecUpd, _ cnsLockPageUpd IsRecordsetLocked = True strErrMsg = Err.Description Case Else MsgBox "An Error has occurred (" & Err.Number & ")" & _ vbCrLf & Err.Description End Select Resume exit_IsRecordsetLocked
End Function
Pat Hartman(MVP) - 26 Nov 2005 17:20 GMT Doesn't Access give you a visual clue when the record is locked by someone else (you don't need your own code)? In the record selector you should see a circle with a line through it if someone else is editing the record.
I didn't examine your code in detail but Access might be taking that long because the UpdateRetryInterval value is set too high. Go to Tools/Options/Advanced and try adjusting it.
> I've read around here and there about record locking and have come up > with kind of an incomplete mixed bag of results. A particular app I'm [quoted text clipped - 83 lines] > > End Function kiln - 26 Nov 2005 22:09 GMT Hi Pat
I don't use record selectors, and if I did they'd probably confuse end users. There is no trappable event that occurs when the record is blocked and the "no" or locked symbol appears. Yes I might have to go that route if there is no bettera alternative but it's crude.
I'd thought too that the update retry setting might speed things up. But it does not. Defaul is 250 ms, changing to 1 ms, the error does not fire for about two seconds.
Really weird that no one seems to know how to fix this, and that so few have even tried to deal with it (I include myself).
> Doesn't Access give you a visual clue when the record is locked by someone > else (you don't need your own code)? In the record selector you should see [quoted text clipped - 43 lines] > > PID > > Set rs = db.OpenRecordset(strSQL, dbOpenDynaset) Albert D.Kallal - 28 Nov 2005 09:23 GMT > Really weird that no one seems to know how to fix this, and that so few > have even tried to deal with it (I include myself). Well, as most mentioned, if you have a record selector bar, it gives a nice visual que..and no code. So, I am not surprised that few make any efforts here, as ms-access can do the job for you.
However, you *can* trap a edit error. Try the following in your on current event....I just wrote this now...but it does work ok....
Private Sub Form_Current()
Dim rst As DAO.Recordset
Set rst = Me.Recordset
If IsNull(Me.ID) = False Then On Error GoTo noedit rst.Edit On Error GoTo 0 End If
Set rst = Nothing
Exit Sub
noedit: Set rst = Nothing
MsgBox "This record is in use by another user, please try later"
End Sub
 Signature Albert D. Kallal (Access MVP) Edmonton, Alberta Canada pleaseNOOSpamKallal@msn.com http://www.members.shaw.ca/AlbertKallal
kiln - 28 Nov 2005 18:02 GMT I never use record selectors on main forms, just like I often don't use the build in nav buttons and a host of other sometimes useful (to me) and sometimes not features that Access comes with. Many of us don't use the all of the built in conveniences, there are often better ways to go about things.
I'm not sure if you read the orig post but I certainly know that the .edit error occurs and is trappable. The problem with .edit is (as mentioned) that it's too slow to fire, I'd call it close to useless. For some reason it takes about two seconds to raise the error, regardless of how tiny, how local, etc etc etc the db and form/rs etc are configured. At least I've not found a way to have it operate as fast as it needs to, I am of course hoping that there is some pattern that makes it "go".
What is not trappable (is not an error) and may or may not be detectable is the record selector "locked" indicator showing up, or more properly whatever internal event invokes the locked icon. It would be really cool if whatever that is was tappable. As you know there are many such workarounds that have been discovered, but as far as I can tell this isn't one of them.
> > Really weird that no one seems to know how to fix this, and that so few > > have even tried to deal with it (I include myself). [quoted text clipped - 28 lines] > > End Sub Albert D.Kallal - 29 Nov 2005 00:19 GMT >I never use record selectors on main forms, just like I often don't use I also don't use reocrd selctors, and in fact my forms *most* of the time are restr5iced to one roecrd....so I do under5tand stand where you are comming form.
> The problem with .edit is (as > mentioned) that it's too slow to fire Have you tried keeping a persisteacnt conenction...does that help?
> What is not trappable (is not an error) and may or may not be detectable > is the record selector "locked" indicator showing up Hum, does the reocrd selector show up any faster then trapping the edit?..(I assume yes in your case).
I would as a last attempt try a persistent connection...that might help (a persistent connection means in your startup code you open up a table to the back end...any table.).
If the above don't work, then you could write your own locking routines....
 Signature Albert D. Kallal (Access MVP) Edmonton, Alberta Canada pleaseNOOSpamKallal@msn.com http://www.members.shaw.ca/AlbertKallal
Pat Hartman(MVP) - 29 Nov 2005 03:25 GMT To each his own. If I wanted to write code to control every little thing, I would be working in VB.Net or C# or anything that paid better and got more respect. The big plus of Access is the things it does for you when you use bound forms. I feel no great compunction to reinvent the wheel or spend my client's money to do it.
It doesn't take much to train users to use the record selector and the navigation buttons. I know most of them are as dumb as slugs but even a slug can find the dish of beer in your garden in which you hope he will drown himself. If a client has a real aversion to the Access standard methods, I write code (or more likely, copy it). Otherwise, I spend my time doing relevant things rather than trying to reproduce something Access takes care of if we simply allow it to.
Before you spend any more time on trapping the record lock, why not try showing the recordselector to see how long that method takes.
Also, I'm not sure the Current event is the correct place to trap the error. You won't "see" the record lock until the other PC reading the record starts editing it since records aren't locked until a change is started. So two PCs could go through the Current event for the same record without experiencing a lock. You may need to trap the error in the form's Dirty event. That event fires as soon as a user types the first character in any field.
>>I never use record selectors on main forms, just like I often don't use > [quoted text clipped - 19 lines] > If the above don't work, then you could write your own locking > routines.... Albert D.Kallal - 29 Nov 2005 07:05 GMT > To each his own. If I wanted to write code to control every little thing, > I would be working in VB.Net or C# or anything that paid better and got > more respect. The big plus of Access is the things it does for you when > you use bound forms. I feel no great compunction to reinvent the wheel or > spend my client's money to do it. I agree with the above assessment.
> Also, I'm not sure the Current event is the correct place to trap the > error. Ditto. My code snip is only a proof of concept. About the "only" use of my code example would be to test to see the "delay" is reduced, or eliminated. If the delay goes away, then I would consider expanding on the .edit idea..but only then... (and, likey the on-dirty event would be a possbile approach).
Depending on the design of the application, rolling ones own locking routines is a reasonable approach. In fact, I wrote a set of routines back for a application I did in access 97. (record locking was at the page level back then).
The criteria for locking code needs to be:
Easy to implement for any form (ie: a generalized solution that requites VERY little code)
The lock table used needs to use the built in locking mechanism to avoid conflicts
The design needs to be such as to not cause any additional bloat to the file.
Since this approach will have a lock table, then the "message" displayed can include the workstation, and user who currently has the record locked.
Only the "parent" record need be locked, since that is the "only" way to edit child records.
I believe that the above design goals are quite easily obtained if certain restrictions in how forms will be used is very obtainable. (My code worked very well for me, and this code continues to be used daily in a a2003 application now).
However, at the end of the day...the comments that one needs to work within the constraints of what ms-access offers is likely the best approach.
I am willing to post my locking code..but it does need some "explain" on how to use it...
 Signature Albert D. Kallal (Access MVP) Edmonton, Alberta Canada pleaseNOOSpamKallal@msn.com http://www.members.shaw.ca/AlbertKallal
kiln - 29 Nov 2005 08:09 GMT > >I never use record selectors on main forms, just like I often don't use > [quoted text clipped - 18 lines] > > If the above don't work, then you could write your own locking routines.... I'll try the persistant connection in the AM. I have seen it make a diff in some situation or other.
The record selector "lock" indicator is virtually instantaneous.
|
|
|