如何解决有没有办法使用 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()
,
由于帖子的字符限制,我无法将这些添加到其他帖子中。以下内容可能有用:
- Introduction to lock files (laccdb and ldb) in Access
- Row-level locking in Access 2000
- ADO.NET Architecture
- System.Data.OleDb Namespace
- OleDbConnection.BeginTransaction Method
- IsolationLevel Enum
- Microsoft OLE DB Provider for Microsoft Jet
- The difference between ODBC,OLE DB,and ADO
- Connect to data in an Access database
- Fundamental Microsoft Jet SQL for Access 2000
- Connection Strings
- ADO.NET Best Practices
- Migrating from ADO to ADO.NET
- VB Helper
- DataTypeEnum
- Microsoft Office Access Database Engine 2007 crashes on a multithreaded application
- CREATE TABLE statement (Microsoft Access SQL)
- Using ADO with Microsoft Visual Basic and Visual Basic for Applications
- Locking Recordsets in Microsoft Access 2000
- Connection object (ADO)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。