Record locking in vba - vba

i have a VBA application which is spitted into two one for front end; and backend while updating how to prevent two users edit it ??

Access has locking. From Access Help:
Specify the locking level used in an Access database in a multiuser environment
On the Tools menu, click Options.
Click the Advanced tab.
To make record-level locking the new
default setting for the current
Microsoft Access database, select the
Open databases using record-level
locking check box.
To make page-level
locking the new default setting for
the current Access database, clear the
Open databases using record level
locking check box.
Notes
This setting takes place the next time
you open the Access database, but you
must use the Open command on the File
menu rather than the list of most
recently used files at the end of the
File menu. This behavior is the same
as the setting for the default open
mode.
If you select Open databases using
record level locking, this becomes the
default behavior for access to data
through a form, a datasheet, and code
that uses a recordset object to loop
through records, but not through
action queries, nor through code that
performs bulk operations using SQL
statements. For more information, see
Chapter 16, "Multiuser Database
Applications," in the Microsoft Office
2000/Visual Basic Programmer's Guide.

Yoy may try to invoke pessimistic locking
Dim cnn As ADODB.Connection
Dim rst As ADODB.Recordset
Set cnn = New ADODB.Connection
cnn.ConnectionString = " Provider=sqloledb;" & _
"Data Source=(local);Initial Catalog=pubs;uid=sa;pwd="
cnn.Open
Set rst = New ADODB.Recordset
rst.ActiveConnection = cnn
rst.CursorType = adOpenKeyset
rst.LockType = adLockPessimistic 'Invoke Pessimistic Locking
rst.CursorLocation = adUseServer
rst.Open "Select * from Table Where ID ='" _
& strID & "'", _
Options:=adCmdText
rst!Name = "New name" 'Lock occurs here
'... when it is locked, you may do other operations
rst.Update 'Lock Released Here
You will have to implement error handling, because when 2nd client wants to edit and cannot lock the record during timeout, error will be raised.
However pessimistic locking is not the best scenario, I would think about optimistic locking and either First Wins or Last Wins strategy
Here is an online book Alison Balter's mastering Microsoft Access 2000 development, it should help you.

Related

MS Access crashes binding RS to a form from SQL Server stored procedure

I am just starting to move our Access DB to SQL Server and am having trouble.
I have a stored procedure that successfully returns rows to an ado recordset.
When I try to bind the rs containing the results of the stored procedure to the Access form, Access crashes without displaying any error messages. I'm on O365 32b and SQL Server 2019.
Here's the code:
Dim sSQL As String, rs As ADODB.Recordset
1 sSQL = "Exec usp_TaskStatusWidget " & Me.Tag & ",0"
2 ADOConn.ConnectionString = conADO
4 ADOConn.Open
6 Set rs = New ADODB.Recordset
7 rs.CursorLocation = adUseClient
8 rs.Open sSQL, ADOConn
10 Set Me.Recordset = rs ' Access crashes here
. . .
Any help would be greatly appreciated!
tia.
SR
Ok, are you previous using ADO, or are you just introducing this?
In most cases, you are better off to just use a view. (replace the access query with a linked view), and then continue useing client side where clauses or filters (access will ONLY pull down the rows you request). So linked views are often a better choice and much less work (in fact, even existing filter for a open report etc. will work and only critera matching the were clause records are pulled.
And in most cases, i don't introduce ADO.
So for a PT query, I often do this:
dim rs as DAO.RecordSet
with CurrentDb.queryDefs("qryPt")
.SQL = "Exec usp_TaskStatusWidget " & Me.Tag & ",0"
set rs = .OpenRecordSet
end with
So, above assumes you have a pt query called qryPt. This also means that you never deal with or worry about connection strings in code. The pt query has the connection. (and your re-link code now can re-link tables and pt queries).
I ONLY suggest the above as a FYI in case that you introducing ADO for calling store procedures, and the rest of the application was previous DAO. If the application was previous DAO, then leave it alone, and use above approach for your PT queries - even code that needs to call store procedures.
Access tends to try and parse the query text to get filters/sorts/etc to work, and if it isn't a plain syntax error but isn't Access SQL either, strange things tend to happen, mostly crashes.
Try adding a comment up front to make sure Access knows not to parse:
sSQL = "-- Access no parse pls" & vbCrLf & "Exec usp_TaskStatusWidget " & Me.Tag & ",0"
The content of the comment is not relevant, of course, its purpose is to immediately cause a syntax error when Access tries to parse it as Access SQL (which doesn't have comments)

Multiple simultaneous connections from excel vba to Access DB

I am building a somewhat complex Excel sheet for a bank, that uses an Access Database.
This sheet loads a ton of data to prebuilt sheets.
After that, they can run a few macros and add some inputs
In the end, I open a new connection to insert these inputs in different tables from the ones that where queried in the beginning
My problem is that when loading the information to the workbook, this action can only be performed by one user at a time.
When this process is running in one user computer other users get the error
The Microsoft Office Access database engine cannot open or write to
the file ''. It is already opened exclusively by another user, or you
need permission to view and write its data.
I know the users have permission because once the process is done on user 1, user 2 has no problem.
I am using ADODB (connection, recordset and command) and this is the code I use about four different times for four different stored queries in access:
Dim cnn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim cmd_apoio As New ADODB.Command
Set cnn = New ADODB.Connection
cnn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source = " & PV.dbpath
With cmd_apoio
.ActiveConnection = cnn
.CommandType = adCmdStoredProc
.CommandText = "tabela_apoio_entidades"
.Parameters.Append .CreateParameter("nip", adNumeric, adParamInput, 20)
.Parameters.Append .CreateParameter("anomes", adNumeric, adParamInput, 20)
.Parameters(0) = PV.nip_grupo
.Parameters(1) = PV.ano_mes
End With
Set rs = cmd_apoio.Execute()
(the PV. variables are public variables declared in another module(PV))
Using this method is there a way to allow multiple connections at once?
Especially as this is only to retrieve information (read-only) and not to update any records in tables.
I am using Excel 2013 and Access 2013, the database is .accdb
EDIT: The tables are linked tables to txt files (i think this might be important)
Try using rs.Open instead of cmd.Execute, and specify the lock type:
After your End With:
Set rs = New ADODB.Recordset
rs.CursorLocation = adUseClient
rs.Open cmd_apoio, cnn, adOpenStatic, adLockOptimistic
You need to set your connection mode explicitly:
Set cnn = New ADODB.Connection
cnn.Mode = 16 + 3 'adModeShareDenyNone + adModeShareReadWrite '
cnn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source = " & PV.dbpath
See here: https://learn.microsoft.com/en-us/sql/ado/reference/ado-api/connectmodeenum
I can only contribute the comments that I've always considered excel not to be multi user.
And in linking Excel to Access - which I've done a lot - the excel must always be closed when working from the Access side. There cannot be a user directly in the Excel - it's role to Access is to behave like a table.
You are in the other direction in using Excel as the front end with Access tables linked - - but in terms of multi user I wonder if the situation is the same.
I am in the same situation as you do, having excel as front-end connecting to data stored in Access.
I kind of solved this multi-user issue by establishing and closing connection on every single action taken by user.
It drags down performance a lot, but I guess it enables concurrent uses.
cnn.Close
Set cnn = Nothing

MS Access Admin State During Statement Execution

Background
I develop a number of tactical data capture tools all of which use the same approach of a split front and back end as below:
Excel VBA forms based front end (using ADO to connect to the back end)
Access 2007 (accdb) database as a back end
My preference would be to use SQL Server as a back end but this is not possible due to restrictions that I am not able to solve.
Each tool distributed has a varying number of users using the tools at the same time (anywhere between 10 - 300+). I understand that Access is not the ideal solution giving the potential number of concurrent users but once again, this is out of my control.
When the tools are in use, users sometimes receive the The database has been placed in a state by user 'Admin' on machine '***' that prevents it from being opened or locked. error.
Given the volume of transactions, the error occurs roughly 0.001% of the time.
I've read a number of articles on the topic, the majority of which end with an assumption that an object within the database is being modified or that a user is entering Design Mode which should be addressed by having a separated front and back end.
Question
A number of different types of queries occur including SELECT and INSERT INTO statements. The users do not directly access the database file and therefore no object as being modified and nothing is being put into Design Mode therefore why are users experiencing this error? Is it due to the shear number of users?
I use the same approach towards connecting to the database using the below method:
Public Function fGetOrderStatus() As Variant()
Dim oDB As ADODB.Connection
Dim oCM As ADODB.Command
Dim oRS As ADODB.Recordset
On Error GoTo Err:
Set oDB = New ADODB.Connection
oDB.Open gcConn
Set oCM = New ADODB.Command
With oCM
.ActiveConnection = oDB
.CommandText = "SELECT OrderStatusId, OrderStatus FROM ct_elh_OrderStatus WHERE Deleted Is Null"
.CommandType = adCmdText
Set oRS = .Execute
End With
If Not oRS.BOF And Not oRS.EOF Then
fGetOrderStatus = oRS.GetRows()
Else
Erase fGetOrderStatus
End If
oRS.Close
Set oRS = Nothing
oDB.Close
Set oDB = Nothing
Exit Function
Err:
MsgBox ("An unexpected error occurred. Please try again later."), vbCritical, "Error"
End Function
The following seems to be the cause of this error:
Jet locks a block of 256 bits in the MDB header. Included in this block of bits are bits that indicate a "passive shutdown", which causes the error message described in the "Symptoms" section to occur. You may have users that open and close the MDB file rapidly and the bits are not getting unlocked quickly enough. When a user tries to open the MDB file, if the program is not able to read the bits, Jet assumes that the user is in a "passive shutdown" or "admin mode", and therefore will not let the user open the MDB file.
It seems this error is due to the fact that you open and close your database to rapidly, especially if there are multiple users involved.
Why not open the connection when opening the user's front-end, and closing the connection when the user wishes to quit?
More information to be found here.

ADODB in Access - Will not insert, but does not raise error

I've been staring at this the past few hours-- I figure now that there is some subtle and devious bug in MySQL causing this, or it's an incredibly obvious solution and I just need another set of eyes. I'd appreciate any help.
I'm using Access to do some data entry work. I have the tables I am working with linked, but I'm primarily dealing with them through explicit ADODB connections (Which will hopefully make transactions easier and allow me to use SELECT ##IDENTITY). The tables are in MySQL on an server within my environment.
I've done similar work before, but for some reason now no updates are made. It doesn't raise an error, I've checked the Connection's error property...for some reason it just breezes through this code without raising an error. The table being referenced is completely empty now, it has quite a few fields but only 2 are that required - an autonumber ID and the field being populated.
Can anyone see something blatantly wrong here? Option Explicit is on, it seems like it's making the connection fine, otherwise I imagine it would error when opening the recordset or connection. Does anyone have any debugging suggestions?
One last note, the code was more complicated - I'm experimenting with making a class to store my connection, to make those things I described easier. My worst-case thought it something I did there, like beginning a transaction without closing it, has caused something to hiccup in MySQL.
Sub ADODBError()
Dim cnn As ADODB.Connection
Set cnn = New ADODB.Connection
cnn.Open "driver={mysql odbc 5.2a driver};" & _
"server=my.mysql.server;" & _
"user=myUser;password=myPwd;" & _
"database=callcenter"
Dim firstDayOfWk As Date
firstDayOfWk = #8/18/2014#
Dim rst As ADODB.Recordset
Set rst = New ADODB.Recordset
rst.Open "WeeklyCallCenterStats", cnn, adOpenForwardOnly, adLockBatchOptimistic, adCmdTable
With rst
.AddNew
.Fields("WeekStarting") = firstDayOfWk
.Update
.Close
End With
End Sub
When you open a ADO recordset in batch locking mode, the changes you make to the recordset are not actually transmitted until you call UpdateBatch on the recordset.
Change the locking mode in your rst.Open call (I recommend adLockOptimistic unless it's a quickly changing table), or call rst.UpdateBatch after making your changes.

Are Access 2010 databases not accessible with Excel if password protected using default encryption (High Security)?

I am currently supporting an Excel 2010 spreadsheet and Access 2010 database that were written by business users. One of the requirements of the Access database is that it be encrypted. It was encrypted with the default encryption settings "Use default encryption(Higher security)" which can be set in Options -> Client Settings.
Now that the database is password protected and encrypted, I am unable to connect to the database through Excel. My testing revolves around importing data into Excel, but what I really need to do is create a row in a log table. I am trying both to import directly to the sheet using the "Data" tab and "From Access" selection and through VBA code. Using the Excel interface, the password dialog box comes up and will never accept the correct password. Using VBA and ADO, the Open statement throws a "not a valid password" error. Both methods work fine if I encrypt the database using the "Use legacy encryption" setting.
I thought it also may be my setup, I'm using Windows 7 32-bit and Office 2010. I have also tried with Windows 8.1 64-bit using Office 2013 with the same results. It works with legacy encryption, but not with default encryption. I didn't try anything earlier. The default higher security encryption was introduced with Office 2010 and Windows 7.
My research has led me to this Technet thread and this Stackoverflow question, both suggesting that Excel cannot interact with Access using the default encryption method. I haven't found a whole lot more discussing this exact issue.
My question to you is does password protecting an Access 2010 database using the default settings really prevent Excel 2010 from importing data (when using the password)? Something about that doesn't sound right to me since sharing data between the two applications is a pretty basic function. I also think that if it were an issue, Google would have turned up more information about it. My guess at this point is that Excel and Access are using the Next Generation encryption engine by default, but that the ADO library has not been updated to use it.
I've attached the connection code for review. For testing I am doing a simple Now() command and emitting the results. The connection fails on the open with a "not a valid password" error even when using the correct password. Works with legacy encryption, not with default encryption.
Sub ADOCNGConnect()
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim ds As String
'setting up connection
Set cn = New ADODB.Connection
With cn
.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source='FILEPATH'" & _
";Jet OLEDB:Database Password=password"
.Open
End With
'setup recordset object
Set rs = New ADODB.Recordset
'retrieve new number
rs.Open "SELECT Now() AS qryTest", cn, adOpenKeyset
MsgBox rs!qryTest
rs.MoveLast
'close ADO object vars
rs.Close: Set rs = Nothing
cn.Close: Set cn = Nothing
End Sub
According to ConnectionStrings.com, the ACE provider doesn't work with the new stronger Access 2010 db encryption:
"Note! Reports say that a database encrypted using Access 2010 - 2013 default encryption scheme does not work with this connection string. In Access; try options and choose 2007 encryption method instead. That should make it work. We do not know of any other solution."
However, that doesn't tell the whole story. Your code worked as an Access VBA procedure and successfully connected to another ACCDB which had the stronger Access 2010 encryption. But I could not find any way to make similar code work as an Excel VBA procedure.
Eventually I abandoned that effort. Since your goal seems to be to make an ADO recordset containing Access data available to Excel, I decided to automate Access and use its CurrentProject.Connection.Execute method to load the recordset.
This may seem kind of clunky, but it works ...
Const cstrPath As String = "C:\Users\hans\Documents\a2010_DbPass_foo.accdb"
Const cstrPwd As String = "foo"
Dim objAccess As Object ' Access.Application
Dim rs As Object ' ADODB.Recordset
Dim strSelect As String
Set objAccess = CreateObject("Access.Application")
objAccess.Visible = True
objAccess.OpenCurrentDatabase cstrPath, , cstrPwd
'strSelect = "SELECT Now() AS qryTest"
strSelect = "SELECT some_text AS qryTest FROM tblFoo"
Set rs = objAccess.CurrentProject.Connection.Execute(strSelect)
MsgBox rs!qryTest
rs.Close
Set rs = Nothing
objAccess.Quit
Set objAccess = Nothing
Note when I used "SELECT Now() AS qryTest" for strSelect, Access crashed at .Quit I don't understand why that happened. But the code worked trouble-free in Excel 2010 as written.