Using @@IDENTITY in a multi user environment

2019-08-29 03:15发布

问题:

The SELECT @@IDENTITY statement in Access VBA, would allow one to view/obtain the AutoNumber that has been generated in a table, for which a record has just been inserted, on the database. This is somewhat easy to track and maintain, if there is just one user and only one INSERT takes place at any moment of time.

My application is multi user, so far only one person used to do data entry. Now we have two people and when one user (Mr Brown) inserts a record (Auto ID : 1234) and within a second (we are dealing with milliseconds) another (Mr Green) INSERTS a record (Auto ID : 1235), the @@IDENTITY seems to return the latest ID 1235 for Mr. Brown and not 1234 which he inserted. As the same Mr. Green gets the same 1235, which is correct.

My Question is, is there a way to make sure that @@IDENTITY return the AutoID of that particular INSERT for that user that performed the INSERT. This is my code, if that helps.

tranDB As DAO.Database
Set tranDB = CurrentDb
tranSQL = "INSERT INTO Transactions (Password....." 'My Insert goes here

tranDB.Execute tranSQL

Dim idRS As DAO.Recordset
Set idRS = tranDB.OpenRecordset("SELECT @@IDENTITY AS LastID;")
TranID = idRS!LastID
idRS.Close
Set idRS = Nothing

EDIT: Not a Duplicate of MS Access TableAdapter Get Identity after insert. As the other thread involves with SQL Server, mine is JET Engine and Not .NET, I am using this code in VBA.

回答1:

Paul have your tried to encapsulate it within a transaction? try this

    Dim tranDB As DAO.Database
    Set tranDB = CurrentDb
    tranSQL = "INSERT INTO Transactions (Password....." 'My Insert goes here

    dbEngine.BeginTrans
    on Error goto ERROR_INSERT:
        tranDB.Execute tranSQL, dbFailOnError

        Dim idRS As DAO.Recordset
        Set idRS = tranDB.OpenRecordset("SELECT @@IDENTITY AS LastID;")
        'ideally put another error trap here
        TranID = nz(idRS("LastID"),0)
    DBEngine.CommitTrans

   On Error resume Next
   idRS.Close
   Set idRS = Nothing
   SET tranDB = nothing
   Exit sub/Function

ERROR_INSERT:
    dbengine.rollback
    'and  other stuffs or resume to exit label


回答2:

Paul,

I have used this technique for forever and it works for me (I would have lost my job many times over if it didn't work!!).

1) You have tagged this as an Access 10 question. So, are you using this reference in your project?:

Microsoft Office 14.0 Access database engine Object Library
C:\Program Files (x86)\Common Files\Microsoft Shared\OFFICE14\ACEDAO.DLL

Older DAO references might be problematic. This feature is not supported before DAO 4.0.

2) Regarding krish's suggestion: transactions, while a good idea, are not required for this feature to work. The last Identity value is locally stored by the current connection. You just have have to call it before the user does another insert.

3) But, it is a good idea to use the same database reference to do both the Insert and retrieve the Identity. In your example, your use of tranDB should be correct -- but if you are re-assigning it to CurrentDB before calling Identity, this could be the problem.

4) Are you using Timestamps to be sure that Brown is inserting before Green?

5) As a last resort, you can try an all-DAO alternative:

'------------------------------------------------------------------------------------------
' The query insert method is used here because DAO respects record-level locking
' on programmatically opened recordsets
'------------------------------------------------------------------------------------------
Set idRs = tranDB.OpenRecordset("SELECT ID, Password, InsertTime FROM Transactions (Password.....", dbOpenDynaset, dbAppendOnly + dbSeeChanges, dbOptimistic)
With idRs
    .AddNew
        !Password = sPassword
        !InsertTime = Now
    .Update
    ' Move to New Record
    .Bookmark = .LastModified
    lIdentity = !ID
    .Close
End With

See if this yields different results.