有没有办法使用 OLEDB 连接锁定记录或表?

问题描述

我正在将旧版 V6 应用程序转换为 VB.NET。 该应用对其数据存储使用多个 Access 2000 mdb。

在大多数情况下,这是一项转换工作,而不是重写,除了 VB.NET 根本不同的地方。 原始编码人员在构建应用的整个过程中学习 VB6 时做出了许多具有挑战性的设计决策。

原始应用程序使用 VB6 中的记录集直接访问数据库。我不知道在 VB.NET 中有什么方法可以做到这一点,所以我使用的是 oledb 连接。 核心要求之一是保持数据库不变,以便两个系统都可以读取它们。到目前为止,这是可能的,但我遇到了以下问题:

该应用(作为其功能之一)跟踪发票和付款。发票编号和付款编号是在保存订单时生成和分配的。

这是通过有一个包含一条记录的状态表来实现的。在存储的数据中,有最后一个发票号和最后一个支付号。存储订单时, 该应用程序将表置于编辑模式以锁定它以防止读取和写入。

DataTables.dbStatus.Recordset.Edit
x = DataTables.dbStatus.Recordset.EditMode

然后它读取数据库获取最后一个发票号和付款号,并在它经过时使用这些数据并保存所有数据并写入新的发票和付款记录。这样做时,它“手动”增加了数字。完成后,它写入了用于记录的新最后一个数字,并做了一个

DataTables.dbStatus.Recordset.Update

要完成更新并解锁表(如果保存期间出现错误,则取消更新,在随后的保存尝试期间执行清理。)

如果其他人在进行另一次保存时尝试保存,应用会捕获锁定的数据库错误,并在重试错误之前重试保存最多 5 次。

这样做的原因是他们可能有两个人同时尝试输入订单。虽然该解决方案无法扩展,但公司规模一直很小,可能尝试保存订单的最大用户数为三个,通常只有两个。

我不知道有什么方法可以使用 oledb 连接数据库访问来复制它。

我查看了事务,但似乎只是在连接(防止线程相互干扰)而不是数据库

在我深入到更多死胡同的兔子洞之前,我会问是否有任何关于我如何实现这一点或类似事情的建议。我越来越倾向于“我们将不得不更改数据库”的解决方案,这会导致整个代码发生许多连锁反应。

用户 9938 的要求预计到达时间

有九个 mdb,每个 mdb 包含许多与 mdb 所代表的区域相关的表格。 没有带有单个表的 mdb。 有问题的 mdb 是 invoice.mdb。 它有大约 50 个表和一个额外的 1w 链接表(用于 Excel 电子表格和其他 mdbs) 有问题的表是 DBstaus 表,它包含具有以下字段的单个记录:

File Year Type: Short text
Archive Year Type: Number LongInt
catalog year Type: Short text
sales changed Type: Date/Time
Last ID Type: Number double
Invoice number Type: Number double
PO number Type: number longint
Payment number Type: number longint
Save Transaction Type: boolean
Last Inventory Date Type: Date/Time
Next Deposit Type: Date/Time
Next Past Due Type: Date/Time
Next Electronic Type: Date/Time
Next Conference Check Type: Date/Time
SS Type: Number long int
Company name Type: Short text
Address1 Type: Short text
Address2 Type: Short text
Phone Type: Short text
EMail Type: Short text
Tax ID Type: Short text

Invoice Number 和 Payment Number 是在应用锁时表当前更新的两个字段。 它们包含上次使用的发票编号和上次使用的付款编号。

解决方法

OP 中提供的信息相当有限。由于您计划继续使用依赖于 DBStatus 中信息的旧版应用程序,正如您所说,有必要使这些信息保持最新,并在您执行操作时防止更新。在不了解您的表和表关系的更多信息的情况下,使用事务可能会起作用 - 如果事务中的任何命令失败,则任何更改都将回滚(撤消)。可能有其他方法可以实现您的目标,但这需要有关您的表(和数据库关系)的更多信息。

尝试以下操作,看看它是否满足您的需求:

注意:您必须添加在创建订单时更新其他表格的代码。

Public Function CreateOrder() As Integer
    'ToDo: add desired code

    Dim invoiceNumber As Double = 0
    Dim paymentNumber As Double = 0
    Dim rowsAffected As Integer = 0

    Try
        'create new instance
        Using cn As OleDbConnection = New OleDbConnection(_connectionStr)
            'open
            cn.Open()

            'create transaction
            Using trx As OleDbTransaction = cn.BeginTransaction()
                Try
                    Try
                        Using cmd As OleDbCommand = New OleDbCommand("SELECT [Invoice Number],[Payment Number] from DBStatus;",cn,trx)
                            Using reader As OleDbDataReader = cmd.ExecuteReader()
                                If reader.HasRows Then
                                    While reader.Read()
                                        'read by position in SQL statement
                                        'If reader(0) IsNot Nothing AndAlso Not IsDBNull(reader(0)) Then
                                        'invoiceNumber = CDbl(reader(0))
                                        'End If

                                        'If reader(1) IsNot Nothing AndAlso Not IsDBNull(reader(1)) Then
                                        'paymentNumber = CDbl(reader(1))
                                        'End If

                                        'read by column name
                                        If reader("Invoice Number") IsNot Nothing AndAlso Not IsDBNull(reader("Invoice Number")) Then
                                            invoiceNumber = CDbl(reader("Invoice Number"))
                                        End If

                                        If reader("Payment Number") IsNot Nothing AndAlso Not IsDBNull(reader("Payment Number")) Then
                                            paymentNumber = CDbl(reader(1))
                                        End If
                                    End While
                                End If
                            End Using
                        End Using
                    Catch ex As OleDbException
                        Debug.WriteLine("Error (CreateOrder - OleDbException 1) - " & ex.Message)
                        Throw ex 're-throw exception
                    Catch ex As Exception
                        Debug.WriteLine("Error (CreateOrder 1) - " & ex.Message)
                        Throw ex 're-throw exception
                    End Try

                    'increment values
                    invoiceNumber += 1
                    paymentNumber += 1

                    'update DBStatus - Invoice Number and Payment Number
                    Try
                        Using cmd As OleDbCommand = New OleDbCommand("UPDATE DBStatus set [Invoice Number] = ?,[Payment Number] = ?",trx)
                            'OLEDB doesn't use named parameters in SQL. Any names specified will be discarded and replaced with '?'
                            'However,specifying names in the parameter 'Add' statement can be useful for debugging
                            'Since OLEDB uses anonymous names,the order which the parameters are added is important
                            'if a column is referenced more than once in the SQL,then it must be added as a parameter more than once
                            'parameters must be added in the order that they are specified in the SQL
                            'if a value is null,the value must be assigned as: DBNull.Value

                            With cmd.Parameters
                                .Add("@invoiceNumber",OleDbType.Double).Value = invoiceNumber
                                .Add("@paymentNumber",OleDbType.Integer).Value = paymentNumber
                            End With

                            'Debug.WriteLine(cmd.CommandText)

                            'ToDo: remove the following code that is for debugging
                            'For Each p As OleDbParameter In cmd.Parameters
                            'Debug.WriteLine(p.ParameterName & ": " & p.Value.ToString())
                            'Next

                            'execute
                            rowsAffected = cmd.ExecuteNonQuery()
                        End Using
                    Catch ex As OleDbException
                        Debug.WriteLine("Error (CreateOrder - OleDbException 2) - " & ex.Message)
                        Throw ex 're-throw exception
                    Catch ex As Exception
                        Debug.WriteLine("Error (CreateOrder 2) - " & ex.Message)
                        Throw ex 're-throw exception
                    End Try

                    Try
                        'ToDo: add code to insert order information

                        Dim sqlText As String = String.Empty

                        If Not String.IsNullOrEmpty(sqlText) Then
                            Using cmd As OleDbCommand = New OleDbCommand(sqlText,trx)

                            End Using
                        End If
                    Catch ex As OleDbException
                        Debug.WriteLine("Error (CreateOrder - OleDbException 3) - " & ex.Message)
                        Throw ex 're-throw exception
                    Catch ex As Exception
                        Debug.WriteLine("Error (CreateOrder 3) - " & ex.Message)
                        Throw ex 're-throw exception
                    End Try

                    'successful
                    'commit transaction,if not commited,any changes (inserts/updates) will be undone
                    trx.Commit()

                Catch ex As OleDbException
                    'rollback transaction
                    trx.Rollback()

                    Debug.WriteLine("Error (CreateOrder - OleDbException trx) - " & ex.Message & "; Transaction rolled back.")
                    Throw ex
                Catch ex As Exception
                    'rollback transaction
                    trx.Rollback()

                    Debug.WriteLine("Error (CreateOrder trx) - " & ex.Message & "; Transaction rolled back.")
                    Throw ex
                End Try
            End Using
        End Using
    Catch ex As OleDbException
        Debug.WriteLine("Error (CreateOrder - OleDbException) - " & ex.Message)
        Throw ex
    Catch ex As Exception
        Debug.WriteLine("Error (CreateOrder) - " & ex.Message)
        Throw ex
    End Try

    Return invoiceNumber
End Function

用法

Dim invoiceNumber As Integer = CreateOrder()

以下是一些可能有用的附加代码:

Imports System.Data.OleDb

Public Class HelperAccess2000

    Private _accessFilename As String = String.Empty
    Private _connectionStr As String = String.Empty

    Public Property AccessFilename
        Get
            Return _accessFilename
        End Get
        Set(value)
            _accessFilename = value

            'initialize
            Initialize(value)
        End Set
    End Property

    Sub New(accessFilename As String)
        'initialize
        Initialize(accessFilename)
    End Sub

    Public Function CreateOrder() As Integer
        'ToDo: add desired code

        Dim invoiceNumber As Double = 0
        Dim paymentNumber As Double = 0
        Dim rowsAffected As Integer = 0

        Try
            'create new instance
            Using cn As OleDbConnection = New OleDbConnection(_connectionStr)
                'open
                cn.Open()

                Using trx As OleDbTransaction = cn.BeginTransaction()
                    Try
                        Try
                            Using cmd As OleDbCommand = New OleDbCommand("SELECT [Invoice Number],trx)
                                Using reader As OleDbDataReader = cmd.ExecuteReader()
                                    If reader.HasRows Then
                                        While reader.Read()
                                            'read by position in SQL statement
                                            'If reader(0) IsNot Nothing AndAlso Not IsDBNull(reader(0)) Then
                                            'invoiceNumber = CDbl(reader(0))
                                            'End If

                                            'If reader(1) IsNot Nothing AndAlso Not IsDBNull(reader(1)) Then
                                            'paymentNumber = CDbl(reader(1))
                                            'End If

                                            'read by column name
                                            If reader("Invoice Number") IsNot Nothing AndAlso Not IsDBNull(reader("Invoice Number")) Then
                                                invoiceNumber = CDbl(reader("Invoice Number"))
                                            End If

                                            If reader("Payment Number") IsNot Nothing AndAlso Not IsDBNull(reader("Payment Number")) Then
                                                paymentNumber = CDbl(reader(1))
                                            End If
                                        End While
                                    End If
                                End Using
                            End Using
                        Catch ex As OleDbException
                            Debug.WriteLine("Error (CreateOrder - OleDbException 1) - " & ex.Message)
                            Throw ex 're-throw exception
                        Catch ex As Exception
                            Debug.WriteLine("Error (CreateOrder 1) - " & ex.Message)
                            Throw ex 're-throw exception
                        End Try

                        'increment values
                        invoiceNumber += 1
                        paymentNumber += 1

                        'update DBStatus - Invoice Number and Payment Number
                        Try
                            Using cmd As OleDbCommand = New OleDbCommand("UPDATE DBStatus set [Invoice Number] = ?,trx)
                                'OLEDB doesn't use named parameters in SQL. Any names specified will be discarded and replaced with '?'
                                'However,specifying names in the parameter 'Add' statement can be useful for debugging
                                'Since OLEDB uses anonymous names,the order which the parameters are added is important
                                'if a column is referenced more than once in the SQL,then it must be added as a parameter more than once
                                'parameters must be added in the order that they are specified in the SQL
                                'if a value is null,the value must be assigned as: DBNull.Value

                                With cmd.Parameters
                                    .Add("@invoiceNumber",OleDbType.Double).Value = invoiceNumber
                                    .Add("@paymentNumber",OleDbType.Integer).Value = paymentNumber
                                End With

                                'Debug.WriteLine(cmd.CommandText)

                                'ToDo: remove the following code that is for debugging
                                'For Each p As OleDbParameter In cmd.Parameters
                                'Debug.WriteLine(p.ParameterName & ": " & p.Value.ToString())
                                'Next

                                'execute
                                rowsAffected = cmd.ExecuteNonQuery()
                            End Using
                        Catch ex As OleDbException
                            Debug.WriteLine("Error (CreateOrder - OleDbException 2) - " & ex.Message)
                            Throw ex 're-throw exception
                        Catch ex As Exception
                            Debug.WriteLine("Error (CreateOrder 2) - " & ex.Message)
                            Throw ex 're-throw exception
                        End Try

                        Try
                            'ToDo: add code to insert order information

                            Dim sqlText As String = String.Empty

                            If Not String.IsNullOrEmpty(sqlText) Then
                                Using cmd As OleDbCommand = New OleDbCommand(sqlText,trx)

                                End Using
                            End If
                        Catch ex As OleDbException
                            Debug.WriteLine("Error (CreateOrder - OleDbException 3) - " & ex.Message)
                            Throw ex 're-throw exception
                        Catch ex As Exception
                            Debug.WriteLine("Error (CreateOrder 3) - " & ex.Message)
                            Throw ex 're-throw exception
                        End Try

                        'successful
                        'commit transaction,any changes (inserts/updates) will be undone
                        trx.Commit()

                    Catch ex As OleDbException
                        'rollback transaction
                        trx.Rollback()

                        Debug.WriteLine("Error (CreateOrder - OleDbException trx) - " & ex.Message & "; Transaction rolled back.")
                        Throw ex
                    Catch ex As Exception
                        'rollback transaction
                        trx.Rollback()

                        Debug.WriteLine("Error (CreateOrder trx) - " & ex.Message & "; Transaction rolled back.")
                        Throw ex
                    End Try
                End Using
            End Using
        Catch ex As OleDbException
            Debug.WriteLine("Error (CreateOrder - OleDbException) - " & ex.Message)
            Throw ex
        Catch ex As Exception
            Debug.WriteLine("Error (CreateOrder) - " & ex.Message)
            Throw ex
        End Try

        Return invoiceNumber
    End Function

    Public Sub Initialize(accessFilename As String)
        'set value
        '_connectionStr = String.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};",accessFilename) 'deprecated
        _connectionStr = String.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};",accessFilename)
    End Sub

    Private Sub ExecuteNonQuery(sqlText As String)

        Using cn As OleDbConnection = New OleDbConnection(_connectionStr)
            'open
            cn.Open()

            Using cmd As OleDbCommand = New OleDbCommand(sqlText,cn)
                'execute
                cmd.ExecuteNonQuery()
            End Using
        End Using
    End Sub

    Private Function TblDBStatusExecuteNonQuery(sqlText As String,invoiceNumber As Double,paymentNumber As Integer) As Integer

        'when specifying value for a string,to pass a null or empty value,specify: "" or Nothing

        Dim rowsAffected As Integer = 0

        'create new instance
        Using cn As OleDbConnection = New OleDbConnection(_connectionStr)
            'open
            cn.Open()

            'create new instance
            Using cmd As OleDbCommand = New OleDbCommand(sqlText,cn)

                'OLEDB doesn't use named parameters in SQL. Any names specified will be discarded and replaced with '?'
                'However,specifying names in the parameter 'Add' statement can be useful for debugging
                'Since OLEDB uses anonymous names,the order which the parameters are added is important
                'if a column is referenced more than once in the SQL,then it must be added as a parameter more than once
                'parameters must be added in the order that they are specified in the SQL
                'if a value is null,the value must be assigned as: DBNull.Value

                With cmd.Parameters
                    .Add("@invoiceNumber",OleDbType.Double).Value = invoiceNumber
                    .Add("@paymentNumber",OleDbType.Integer).Value = paymentNumber
                End With

                'ToDo: remove the following code that is for debugging
                'For Each p As OleDbParameter In cmd.Parameters
                'Debug.WriteLine(p.ParameterName & ": " & p.Value.ToString())
                'Next

                'execute
                rowsAffected = cmd.ExecuteNonQuery()
            End Using
        End Using

        Return rowsAffected
    End Function

    Private Function TblDBStatusExecuteNonQuery(sqlText As String,fileYear As String,archiveYear As Integer,catalogYear As String,salesChanged As DateTime,lastId As Double,poNumber As Integer,paymentNumber As Integer,saveTransaction As Boolean,lastInventory As DateTime,nextDeposit As DateTime,nextPastDue As DateTime,nextElectronic As DateTime,nextConference As DateTime,ss As Integer,companyName As String,address1 As String,address2 As String,phone As String,email As String,taxId As String) As Integer
        'use for INSERT / UPDATE 

        'when specifying value for a string,the value must be assigned as: DBNull.Value

                With cmd.Parameters
                    .Add("@fileYear",OleDbType.VarWChar).Value = If(String.IsNullOrEmpty(fileYear),DBNull.Value,fileYear)
                    .Add("@archiveYear",OleDbType.Integer).Value = archiveYear
                    .Add("@catalogYear",OleDbType.VarWChar).Value = If(String.IsNullOrEmpty(catalogYear),catalogYear)
                    .Add("@salesChanged",OleDbType.Date).Value = salesChanged
                    .Add("@lastId",OleDbType.Double).Value = lastId
                    .Add("@invoiceNumber",OleDbType.Double).Value = invoiceNumber
                    .Add("@poNumber",OleDbType.Integer).Value = poNumber
                    .Add("@paymentNumber",OleDbType.Integer).Value = paymentNumber
                    .Add("@saveTransaction",OleDbType.Boolean).Value = saveTransaction
                    .Add("@lastInventory",OleDbType.Date).Value = lastInventory
                    .Add("@nextDeposit",OleDbType.Date).Value = nextDeposit
                    .Add("@nextPastDue",OleDbType.Date).Value = nextPastDue
                    .Add("@nextElectronic",OleDbType.Date).Value = nextElectronic
                    .Add("@nextConference",OleDbType.Date).Value = nextConference
                    .Add("@ss",OleDbType.Integer).Value = ss
                    .Add("@companyName",OleDbType.VarWChar).Value = If(String.IsNullOrEmpty(companyName),companyName)
                    .Add("@address1",OleDbType.VarWChar).Value = If(String.IsNullOrEmpty(address1),address1)
                    .Add("@address2",OleDbType.VarWChar).Value = If(String.IsNullOrEmpty(address2),address2)
                    .Add("@phone",OleDbType.VarWChar).Value = If(String.IsNullOrEmpty(phone),phone)
                    .Add("@email",OleDbType.VarWChar).Value = If(String.IsNullOrEmpty(email),email)
                    .Add("@taxId",OleDbType.VarWChar).Value = If(String.IsNullOrEmpty(taxId),taxId)
                End With

                'ToDo: remove the following code that is for debugging
                'For Each p As OleDbParameter In cmd.Parameters
                'Debug.WriteLine(p.ParameterName & ": " & p.Value.ToString())
                'Next

                'execute
                rowsAffected = cmd.ExecuteNonQuery()
            End Using
        End Using

        Return rowsAffected
    End Function

    Public Function TblDBStatusInsert(invoiceNumber As Double,paymentNumber As Integer) As Integer
        'insert Invoice Number and Payment Number into DBStatus

        Dim sqlText As String = "INSERT INTO DBStatus([Invoice Number],[Payment Number]) VALUES (?,?);"

        Try
            'insert
            Return TblDBStatusExecuteNonQuery(sqlText,invoiceNumber,paymentNumber)
        Catch ex As OleDbException
            Debug.WriteLine("Error (TblDBStatusInsert - OleDbException) - " & ex.Message & "(" & sqlText & ")")
            Throw ex
        Catch ex As Exception
            Debug.WriteLine("Error (TblDBStatusInsert) - " & ex.Message & "(" & sqlText & ")")
            Throw ex
        End Try
    End Function

    Public Function TblDbStatusGetInvoiceNumberAndPaymentNumber() As DataTable
        'get Invoice Number and Payment Number from DBStatus

        Dim dt As DataTable = New DataTable()
        Dim sqlText As String = "SELECT [Invoice Number],[Payment Number] from DBStatus;"

        Try
            Using con As OleDbConnection = New OleDbConnection(_connectionStr)
                'open
                con.Open()

                Using cmd As OleDbCommand = New OleDbCommand(sqlText,con)
                    Using da As OleDbDataAdapter = New OleDbDataAdapter(cmd)
                        'fill DataTable from database
                        da.Fill(dt)
                    End Using
                End Using
            End Using

            Return dt
        Catch ex As OleDbException
            Debug.WriteLine("Error (TblDbStatusGetInvoiceNumberAndPaymentNumber - OleDbException) - " & ex.Message & "(" & sqlText & ")")
            Throw ex
        Catch ex As Exception
            Debug.WriteLine("Error (TblDbStatusGetInvoiceNumberAndPaymentNumber) - " & ex.Message & "(" & sqlText & ")")
            Throw ex
        End Try
    End Function

    Public Function TblDBStatusUpdate(invoiceNumber As Double,paymentNumber As Integer) As Integer
        'update Invoice Number and Payment Number in DBStatus

        Dim sqlText As String = "UPDATE DBStatus set [Invoice Number] = ?,[Payment Number] = ?;"

        Try
            'update
            Return TblDBStatusExecuteNonQuery(sqlText,paymentNumber)
        Catch ex As OleDbException
            Debug.WriteLine("Error (TblDBStatusUpdate - OleDbException) - " & ex.Message & "(" & sqlText & ")")
            Throw ex
        Catch ex As Exception
            Debug.WriteLine("Error (TblDBStatusUpdate) - " & ex.Message & "(" & sqlText & ")")
            Throw ex
        End Try
    End Function

    Public Function TblDBStatusUpdate(fileYear As String,taxId As String) As Integer
        'update Invoice Number and Payment Number in DBStatus

        Dim sqlText As String = "UPDATE DBStatus set [File Year] = ?,[Archive Year] = ?,[Catalog Year] = ?,[Sales Changed] = ?,[Last ID] = ?,[Invoice Number] = ?,[PO Number] = ?,[Payment Number] = ?,[Save Transaction] = ?,[Last Inventory] = ?,[Next Deposit] = ?,[Next Past Due] = ?,[Next Electronic] = ?,[Next Conference] = ?,SS = ?,[Company Name] = ?,Address1 = ?,Address2 = ?,Phone = ?,EMail = ?,[Tax ID] = ?;"

        Try
            'update
            Return TblDBStatusExecuteNonQuery(sqlText,fileYear,archiveYear,catalogYear,salesChanged,lastId,poNumber,paymentNumber,saveTransaction,lastInventory,nextDeposit,nextPastDue,nextElectronic,nextConference,ss,companyName,address1,address2,phone,email,taxId)
        Catch ex As OleDbException
            Debug.WriteLine("Error (TblDBStatusUpdate - OleDbException) - " & ex.Message & "(" & sqlText & ")")
            Throw ex
        Catch ex As Exception
            Debug.WriteLine("Error (TblDBStatusUpdate) - " & ex.Message & "(" & sqlText & ")")
            Throw ex
        End Try
    End Function
End Class

用法

Private _accessFilename As String = "C:\Temp\TestAccess2000.mdb"
Private _helper As HelperAccess2000 = Nothing
              
Private Sub InitializeHelper()
    If _helper Is Nothing Then
        'create new instance
        _helper = New HelperAccess2000(_accessFilename)
    End If
End Sub
               ...

InitializeHelper()

Dim rowsAffected As Integer = 0

rowsAffected = _helper.TblDBStatusInsert("1","3")
rowsAffected = _helper.TblDBStatusUpdate("2","4")

Dim invoiceNumber As Integer = _helper.CreateOrder()
Dim dt As DataTable = _helper.TblDbStatusGetInvoiceNumberAndPaymentNumber()
,

由于帖子的字符限制,我无法将这些添加到其他帖子中。以下内容可能有用: