ms access - مصر - مس(جت) المعاملات، مساحات العمل




مساحة عمل مشتركة الرياض (2)

حسنا، بعد الكثير من التصحيح محبط، وأعتقد أنني كشفت علة في المعاملات جت. بعد كل ذلك، لا علاقة له مع بلدي "ملتوية بشكل كبير" رمز أو "المتغيرات العالمية الشر" :)

يبدو أنه عندما يكون ما يلي صحيحا، تحصل على الخطأ # 3034:

  • فتح مجموعة سجلات من نوع لقطة
  • يتم فتح مجموعة السجلات قبل بدء المعاملة
  • يتم إغلاق مجموعة السجلات / ديريفيرنسد بعد بدء المعاملة، ولكن قبل ارتكاب أو التراجع.

أنا لم تحقق إذا كان هذا هو معروف بالفعل، على الرغم من أنني لا يمكن أن نتصور أنها ليست كذلك.

وبطبيعة الحال، فإنه من الغريب أن تفعل أشياء في هذا النظام على أي حال وطلب من المتاعب، وأنا لا أعرف لماذا فعلت ذلك. انتقلت فتح / إغلاق مجموعة سجلات لقطة إلى داخل الصفقة وكل شيء يعمل بشكل جيد.

تظهر التعليمات البرمجية التالية الخطأ:

Public Sub run()
Dim db As DAO.Database, qdf As DAO.QueryDef, rst As DAO.Recordset
Dim wrk As DAO.Workspace, isInTrans As Boolean
On Error GoTo Err_

    Set wrk = DBEngine(0)
    Set db = wrk(0)
    Set rst = db.OpenRecordset("Table2", DAO.dbOpenSnapshot)

    wrk.BeginTrans
    isInTrans = True

    Set qdf = db.CreateQueryDef("", "INSERT INTO [Table1] (Field1, Field2) VALUES (""Blow"", ""Laugh"");")
    qdf.Execute dbFailOnError

Exit_:
    Set rst = Nothing
    Set qdf = Nothing
    Set db = Nothing
    If isInTrans Then wrk.CommitTrans
    isInTrans = False
    Exit Sub

Err_:
    MsgBox Err.Description
    If isInTrans Then wrk.Rollback
    isInTrans = False
    Resume Exit_

End Sub

وهذا يثبت الخطأ:

Public Sub run()
Dim db As DAO.Database, qdf As DAO.QueryDef, rst As DAO.Recordset
Dim wrk As DAO.Workspace, isInTrans As Boolean
On Error GoTo Err_

    Set wrk = DBEngine(0)
    Set db = wrk(0)

    wrk.BeginTrans
    isInTrans = True

    ' NOTE THIS LINE MOVED WITHIN THE TRANSACTION
    Set rst = db.OpenRecordset("Table2", DAO.dbOpenSnapshot)

    Set qdf = db.CreateQueryDef("", "INSERT INTO [Table1] (Field1, Field2) VALUES (""Blow"", ""Laugh"");")
    qdf.Execute dbFailOnError

Exit_:
    Set rst = Nothing
    Set qdf = Nothing
    Set db = Nothing
    If isInTrans Then wrk.CommitTrans
    isInTrans = False
    Exit Sub

Err_:
    MsgBox Err.Description
    If isInTrans Then wrk.Rollback
    isInTrans = False
    Resume Exit_

End Sub

أواجه مشكلة في إجراء معاملة (باستخدام أسيس 2003 داو). انها تتصرف كما لو لم أكن قد دعا بيجينترانز - أحصل على خطأ 3034 على كوميترانز، "حاولت ارتكاب أو التراجع عن معاملة دون بدء أول معاملة" . ويتم كتابة التغييرات إلى قاعدة البيانات (ربما لأنهم لم يلفوا أبدا في معاملة). ومع ذلك، يتم تشغيل بيجينترانز، إذا كنت خطوة من خلال ذلك.

  • أنا تشغيله ضمن بيئة أسيس باستخدام مساحة العمل دبنجين (0).
  • يتم فتح الجداول التي قمت بإضافة سجلات إلى كافة عبر اتصال قاعدة بيانات جت (إلى نفس قاعدة البيانات) واستخدام DAO.Recordset.AddNew / أوبديت.
  • يتم فتح الاتصال قبل بدء بيفورترانز.
  • أنا لا أفعل أي شيء غريب في منتصف الصفقة مثل إغلاق / فتح اتصالات أو مساحات عمل متعددة الخ
  • هناك نوعان من مستويات المعاملات المتداخلة. في الأساس انها التفاف إدراج متعددة في معاملة خارجية، لذلك إذا فشل أي فشل كل ذلك. المعاملات الداخلية تشغيل دون أخطاء، انها الصفقة الخارجية التي لا تعمل.

وفيما يلي بعض الأشياء التي بحثت واستبعدت:

  • وتنتشر الصفقة عبر عدة طرق و بيجينترانز و كومترانز (والتراجع) كلها في أماكن مختلفة. ولكن عندما حاولت اختبار بسيط لتشغيل الصفقة بهذه الطريقة، فإنه لا يبدو أن هذا ينبغي أن يهم.

  • اعتقدت ربما يتم الحصول على اتصال قاعدة البيانات مغلقة عندما يخرج من النطاق المحلي، على الرغم من أن لدي إشارة 'العالمية' آخر إلى ذلك (أنا أبدا متأكدا ما داو يفعل مع اتصالات دبس أن نكون صادقين). ولكن هذا لا يبدو أن يكون الحال - الحق قبل ارتكاب، والاتصال وسجلاتها على قيد الحياة (يمكنني التحقق من خصائصها، إوف = خطأ، وما إلى ذلك)

  • يتم القيام كومتيترانز والاستعادة ضمن عمليات الاستدعاء الحدث. (في الأساس: برنامج المحلل هو رمي الحدث 'أونلواد' في نهاية التحليل، الذي أنا التعامل مع إما ارتكاب أو التراجع إدراج أدليت به أثناء المعالجة، وهذا يتوقف على إذا حدث أي أخطاء.) ومع ذلك، مرة أخرى، في محاولة اختبار بسيط، فإنه لا يبدو مثل هذا ينبغي أن يهم.

أي أفكار لماذا هذا لا يعمل بالنسبة لي؟

شكر.

إديت 25 ماي

هنا هو رمز (مبسط). النقاط الرئيسية التي لها علاقة بالمعاملة هي:

  • مساحة العمل هي دبنجين (0)، المشار إليها ضمن المتغير العام (العالمي) APPSESSION .
  • يتم فتح اتصال قاعدة البيانات في LoadProcess.cache أدناه، راجع السطر Set db = APPSESSION.connectionTo(dbname_) .
  • يسمى بيجينترانز في LoadProcess.cache.
  • ويسمى كومترانز في عملية__onLoad استدعاء.
  • يتم استدعاء التراجع في عملية__on الرد غير صحيح.
  • يتم إجراء تحديثات مجموعة السجلات في العملية__onLoadRow و لوغلودينيت و لوغلود

اريك

'------------------- 
'Application globals
'-------------------

Public APPSESSION As DAOSession

'------------------
' Class LoadProcess
'------------------

Private WithEvents process_ As EventedParser
Private errs_ As New Collection

Private dbname_ As String
Private rawtable_ As String
Private logtable_ As String
Private isInTrans_ As Integer

Private raw_ As DAO.Recordset
Private log_ As DAO.Recordset
Private logid_ As Variant

Public Sub run
    '--- pre-load
    cache
    resetOnRun    ' resets load state variables per run, omitted here
    logLoadInit
    Set process_ = New EventedParser

    '--- load
    process_.Load
End Sub

' raised once per load() if any row invalid
Public Sub process__onInvalid(filename As String)
    If isInTrans_ Then APPSESSION.Workspace.Rollback
End Sub

' raised once per load() if all rows valid, after load
Public Sub process__onLoad(filename As String)
    If errs_.Count > 0 Then
        logLoadFail filename, errs_
    Else
        logLoadOK filename
    End If

    If isInTrans_ Then APPSESSION.Workspace.CommitTrans
End Sub

' raised once per valid row
' append data to raw_ recordset
Public Sub process__onLoadRow(row As Dictionary)
On Error GoTo Err_

    If raw_ Is Nothing Then GoTo Exit_   
    DAOext.appendFromHash raw_, row, , APPSESSION.Workspace

Exit_:
    Exit Sub

Err_:
    ' runtime error handling done here, code omitted
    Resume Exit_

End Sub


Private Sub cache()
Dim db As DAO.Database

    ' TODO raise error
    If Len(dbname_) = 0 Then GoTo Exit_       
    Set db = APPSESSION.connectionTo(dbname_)
    ' TODO raise error
    If db Is Nothing Then GoTo Exit_ 

    Set raw_ = db.OpenRecordset(rawtable_), dbOpenDynaset)
    Set log_ = db.OpenRecordset(logtable_), dbOpenDynaset)    

    APPSESSION.Workspace.BeginTrans
    isInTrans_ = True

Exit_:
    Set db = Nothing

End Sub

' Append initial record to log table
Private Sub logLoadInit()
Dim info As New Dictionary
On Error GoTo Err_

    ' TODO raise error?
    If log_ Is Nothing Then GoTo Exit_   

    With info
        .add "loadTime", Now
        .add "loadBy", CurrentUser
    End With

    logid_ = DAOext.appendFromHash(log_, info, , APPSESSION.Workspace)

Exit_:
    Exit Sub

Err_:
    ' runtime error handling done here, code omitted
    Resume Exit_

End Sub

Private Sub logLoadOK(filename As String)
    logLoad logid_, True, filename, New Collection
End Sub

Private Sub logLoadFail(filename As String, _
                      errs As Collection)
    logLoad logid_, False, filename, errs
End Sub

' Update log table record added in logLoadInit
Private Sub logLoad(logID As Variant, _
                    isloaded As Boolean, _
                    filename As String, _
                    errs As Collection)

Dim info As New Dictionary
Dim er As Variant, strErrs As String
Dim ks As Variant, k As Variant
On Error GoTo Err_

    ' TODO raise error?
    If log_ Is Nothing Then GoTo Exit_   
    If IsNull(logID) Then GoTo Exit_

    For Each er In errs
        strErrs = strErrs & IIf(Len(strErrs) = 0, "", vbCrLf) & CStr(er)
    Next Er

    With info
        .add "loadTime", Now
        .add "loadBy", CurrentUser
        .add "loadRecs", nrecs
        .add "loadSuccess", isloaded
        .add "loadErrs", strErrs
        .add "origPath", filename
    End With

    log_.Requery
    log_.FindFirst "[logID]=" & Nz(logID)
    If log_.NoMatch Then
        'TODO raise error
    Else
        log_.Edit
        ks = info.Keys
        For Each k In ks
            log_.Fields(k).Value = info(k)
        Next k
        log_.Update
    End If

Exit_:
    Exit Sub

Err_:
    ' runtime error handling done here, code omitted
    Resume Exit_

End Sub


'-------------
' Class DAOExt
'-------------
' append to recordset from Dictionary, return autonumber id of new record
Public Function appendFromHash(rst As DAO.Recordset, _
                          rec As Dictionary, _
                          Optional map As Dictionary, _
                          Optional wrk As DAO.workspace) As Long
Dim flds() As Variant, vals() As Variant, ifld As Long, k As Variant
Dim f As DAO.Field, rst_id As DAO.Recordset
Dim isInTrans As Boolean, isPersistWrk As Boolean
On Error GoTo Err_

    ' set up map (code omitted here)

    For Each k In rec.Keys
        If Not map.Exists(CStr(k)) Then _
            Err.Raise 3265, "appendFromHash", "No field mapping found for [" & CStr(k) & "]"
        flds(ifld) = map(CStr(k))
        vals(ifld) = rec(CStr(k))
        ifld = ifld + 1
    Next k

    If wrk Is Nothing Then
        isPersistWrk = False
        Set wrk = DBEngine(0)
    End If

    wrk.BeginTrans
        isInTrans = True
        rst.AddNew
        With rst
            For ifld = 0 To UBound(flds)
                .Fields(flds(ifld)).Value = vals(ifld)
            Next ifld
        End With
        rst.Update

        Set rst_id = wrk(0).OpenRecordset("SELECT @@Identity", DAO.dbOpenForwardOnly, DAO.dbReadOnly)
        appendFromHash = rst_id.Fields(0).Value

    wrk.CommitTrans
    isInTrans = False

Exit_:
    On Error GoTo 0
    If isInTrans And Not wrk Is Nothing Then wrk.Rollback
    If Not isPersistWrk Then Set wrk = Nothing
    Exit Function

Err_:
    ' runtime error handling, code omitted here
    Resume Exit_

End Function


'-----------------
' Class DAOSession (the part that deals with the workspace and dbase connections)
'-----------------
Private wrk_ As DAO.workspace
Private connects_ As New Dictionary
Private dbs_ As New Dictionary

Public Property Get workspace() As DAO.workspace
    If wrk_ Is Nothing Then
        If DBEngine.Workspaces.Count > 0 Then
            Set wrk_ = DBEngine(0)
        End If
    End If
    Set workspace = wrk_
End Property

Public Property Get connectionTo(dbname As String) As DAO.database
    connectTo dbname
    Set connectionTo = connects_(dbname)
End Property

Public Sub connectTo(dbname As String)
Dim Cancel As Integer
Dim cnn As DAO.database
Dim opts As Dictionary
    Cancel = False

    ' if already connected, use cached reference
    If connects_.Exists(dbname) Then GoTo Exit_

    If wrk_ Is Nothing Then _
        Set wrk_ = DBEngine(0)

    ' note opts is a dictionary of connection options, code omitted here
    Set cnn = wrk_.OpenDatabase(dbs_(dbname), _
                                CInt(opts("DAO.OPTIONS")), _
                                CBool(opts("DAO.READONLY")), _
                                CStr(opts("DAO.CONNECT")))

    ' Cache reference to dbase connection
    connects_.Add dbname, cnn

Exit_:
    Set cnn = Nothing
    Exit Sub

End Sub

لما يستحق هذا يبدو أن أكثر انتشارا قليلا من مجرد الوصول إلى المعاملات. لقد واجهت للتو حالة مماثلة باستخدام أسيس 2007 و داو بمثابة الواجهة الأمامية ل ميسكل. مع ميسكل Autocommit=0 ، ومعاملات سكل مع ذلك تلتزم غامضة أنفسهم في منتصف الطريق من خلال الصفقة.

بعد 2 أسابيع من خدش الرأس جئت عبر هذا المنصب ونظرت في رمز بلدي مرة أخرى. ومن المؤكد أن يتم إدراج إدراج الخلية من خلال إجراء المخزنة التي كانت تسمى من داخل وحدة فئة فبا. كانت هذه الوحدة النمطية فئة dao.recordset التي تم فتحها على module.initialize() وأغلقت عند terminate() . علاوة على ذلك، تم استخدام مجموعة السجلات هذه لجمع نتائج الإجراء المخزن. حتى كان لي (في رمز الزائفة ...)

module.initialize - rs.open

class properties set by external functions

transaction.begins

Mysql procedure.calls using class properties as parameters - 

commit(or rollback)

rs.populate

class properties.set

properties used by external functions

module terminate - rs.close

وكانت المعاملات لا تعمل فقط. حاولت كل شيء يمكن تخيله لمدة 2 أسابيع. مرة واحدة أعلنت وأغلقت روبية داخل الصفقة كل شيء عملت تماما!