• Trick: 巧用.NET Reflector, SOS Debugging找出和某一个TransactionScope绑定的SqlConnection objects以及SqlConnection中开着的SqlDataReader objects (Find all SqlConnection objects associated with a TransactionScope)


    考虑一下如下两个问题:

    Q1: How to find the live SqlDataReader from a SqlConnection object.
    Q2: How to find all SqlConnection objects associated with a TransactionScope, and then find the live SqlDataReader from the SqlConnection objects.

    Q1 相对容易。你可以使用.NET Reflection轻松解决。具体参见我的这篇blog:
    Trick: 巧用.NET Reflection从SqlConnection回溯到打开着的SqlDataReader。(Find the live SqlDataReader from SqlConnection)

    Q2 难在TransactionScope 或Transaction中不含任何public/internal members 阐明和当前TransactionScope相关联的SqlConnection 对象集合。Q1中的解决方案在Q2就不起作用了。

    要解决Q2,你需要司马缸砸光的思维:

    基本的想法是使用SOS debugging dump出managed heap中所有的SqlConnection对象,然后逐一检查他们是否和某一个Transaction对象相关联。

    首先,我们按照这篇文章在Visual Studio里配置并加载SOS。Configure完以后,我们打印出所有SqlConnection对象:

    !DumpHeap -type System.Data.SqlClient.SqlConnection
    Address       MT     Size
    01e685c0 0447d75c       56    
    01e68604 0447ebac       32    
    01eabdf8 0447f3c4      112    
    01eacf30 0447f6e0       28    
    total 4 objects
    Statistics:
          MT    Count    TotalSize Class Name
    0447f6e0        1           28 System.Data.SqlClient.SqlConnectionPoolGroupProviderInfo
    0447ebac        1           32 System.Data.SqlClient.SqlConnectionFactory
    0447d75c        1           56 System.Data.SqlClient.SqlConnection
    0447f3c4        1          112 System.Data.SqlClient.SqlConnectionString
    Total 4 objects

    From the output, we see that the method table of System.Data.SqlClient.SqlConnection is 044fd75c, and there is currently only one SqlConnection object in the managed heap (in your case, you may see a lot of SqlConnection objects). Then we get each SqlConnection object’s address:

    Address       MT     Size
    01e685c0 0447d75c       56
       

    然后,打印每一个SqlConnection对象:

    !do 01e685c0
    Name: System.Data.SqlClient.SqlConnection
    MethodTable: 0447d75c
    EEClass: 0439c1e4
    Size: 56(0x38) bytes
    (C:\Windows\assembly\GAC_32\System.Data\2.0.0.0__b77a5c561934e089\System.Data.dll)
    Fields:
          MT    Field   Offset                 Type VT     Attr    Value Name
    63160508  400018a        4        System.Object  0 instance 00000000 __identity
    654829d8  40008c3        8 ...ponentModel.ISite  0 instance 00000000 site
    6549ccac  40008c4        c ....EventHandlerList  0 instance 00000000 events
    63160508  40008c2      108        System.Object  0   static 01eb07a4 EventDisposed
    04899008  4000bd6       10 ...hangeEventHandler  0 instance 00000000 _stateChangeEventHandler
    048bdc58  400171c       14 ...t.SqlDebugContext  0 instance 00000000 _sdc
    631343b8  400171d       30       System.Boolean  1 instance        0 _AsycCommandInProgress
    04480e84  400171e       18 ...ent.SqlStatistics  0 instance 00000000 _statistics
    631343b8  400171f       31       System.Boolean  1 instance        0 _collectstats
    631343b8  4001720       32       System.Boolean  1 instance        0 _fireInfoMessageEventOnUserErrors
    0447f410  4001723       1c ...ConnectionOptions  0 instance 01eabdf8 _userConnectionOptions
    0447ef50  4001724       20 ...nnectionPoolGroup  0 instance 01eacef4 _poolGroup
    0447f54c  4001725       24 ...onnectionInternal  0 instance 01eb3654 _innerConnection
    63162b38  4001726       28         System.Int32  1 instance        0 _closeCount
    63162b38  4001728       2c         System.Int32  1 instance        1 ObjectID
    63160508  400171b      798        System.Object  0   static 01e685f8 EventInfoMessage
    0447edbc  4001721      79c ...ConnectionFactory  0   static 01e68604 _connectionFactory
    631626b4  4001722      7a0 ...eAccessPermission  0   static 01e90d98 ExecutePermission
    63162b38  4001727      880         System.Int32  1   static        1 _objectTypeCount

    红颜色标记的是其中的 _innerConnection 对象。通过.NET Reflector,我们可以看到它的类型是DbConnectionInternal。继续dump这个对象:

    !do 01eb3654
    Name: System.Data.SqlClient.SqlInternalConnectionTds
    MethodTable: 0448134c
    EEClass: 043b0d04
    Size: 140(0x8c) bytes
    (C:\Windows\assembly\GAC_32\System.Data\2.0.0.0__b77a5c561934e089\System.Data.dll)
    Fields:
          MT    Field   Offset                 Type VT     Attr    Value Name
    63162b38  4000f7b       1c         System.Int32  1 instance        4 _objectID
    631343b8  4000f7e       28       System.Boolean  1 instance        0 _allowSetConnectionString
    631343b8  4000f7f       29       System.Boolean  1 instance        1 _hidePassword
    04897830  4000f80       20         System.Int32  1 instance        1 _state
    6315a09c  4000f81        4 System.WeakReference  0 instance 01eb379c _owningObject
    0447f54c  4000f82        8 ...onnectionInternal  0 instance 00000000 _nextPooledObject
    0447f088  4000f83        c ....DbConnectionPool  0 instance 01eb12dc _connectionPool
    0447ec80  4000f84       10 ...ctionPoolCounters  0 instance 01e68624 _performanceCounters
    044821a4  4000f85       14 ...ferenceCollection  0 instance 01ebeda0 _referenceCollection
    63162b38  4000f86       24         System.Int32  1 instance        0 _pooledCount
    631343b8  4000f87       2a       System.Boolean  1 instance        0 _connectionIsDoomed
    631343b8  4000f88       2b       System.Boolean  1 instance        0 _cannotBePooled
    631343b8  4000f89       2c       System.Boolean  1 instance        0 _isInStasis
    63137f4c  4000f8a       30      System.DateTime  1 instance 01eb3684 _createTime
    677dcebc  4000f8b       18 ...tions.Transaction  0 instance 00000000 _enlistedTransaction ‘ In my demo, I did not associate the connection with any transaction, so here it is null. But if it’s associated, you can !do the transaction object, get its internalTransaction object and check whether it’s the same object as the TransactionScope’s transaction object.
    63162b38  4000f7a      554         System.Int32  1   static        4 _objectTypeCount
    0447f5d4  4000f7c      348 ...teChangeEventArgs  0   static 01eabd38 StateChangeClosed
    0447f5d4  4000f7d      34c ...teChangeEventArgs  0   static 01eabd48 StateChangeOpen
    0447f3c4  40018b0       38 ...lConnectionString  0 instance 01eabdf8 _connectionOptions
    631608ec  40018b1       3c        System.String  0 instance 01eb8af8 _currentDatabase
    631608ec  40018b2       40        System.String  0 instance 01eac1c4 _currentDataSource
    631343b8  40018b3       54       System.Boolean  1 instance        0 _isEnlistedInTransaction
    6316335c  40018b4       44        System.Byte[]  0 instance 00000000 _promotedDTCToken
    04483a98  40018b5       48 ...egatedTransaction  0 instance 00000000 _delegatedTransaction
    6316335c  40018b6       4c        System.Byte[]  0 instance 00000000 _whereAbouts
    677dcebc  40018b7       50 ...tions.Transaction  0 instance 00000000 _contextTransaction
    0447f6e0  40018c6       58 ...GroupProviderInfo  0 instance 01eacf30 _poolGroupProviderInfo
    044814ac  40018c7       5c ...lClient.TdsParser  0 instance 01eb3fbc _parser
    04481c8c  40018c8       60 ...lient.SqlLoginAck  0 instance 01eb968c _loginAck
    631343b8  40018c9       55       System.Boolean  1 instance        1 _fConnectionOpen
    631343b8  40018ca       56       System.Boolean  1 instance        1 _fResetConnection
    631608ec  40018cb       64        System.String  0 instance 01eb8af8 _originalDatabase
    631608ec  40018cc       68        System.String  0 instance 00000000 _currentFailoverPartner
    631608ec  40018cd       6c        System.String  0 instance 01eb9578 _originalLanguage
    631608ec  40018ce       70        System.String  0 instance 01eb9578 _currentLanguage
    63162b38  40018cf       80         System.Int32  1 instance     8000 _currentPacketSize
    63162b38  40018d0       84         System.Int32  1 instance        0 _asyncCommandCount
    631608ec  40018d1       74        System.String  0 instance 01de1198 _instanceName
    04480fec  40018d2       78 ...ctionPoolIdentity  0 instance 00000000 _identity
    00000000  40018d3       7c                       0 instance 00000000 _preparedCommands

    任然请注意上诉dump中红色加亮的部分。_enlistedTransaction 可以帮我们找到与当前SqlConnection相关联的Transaction对象。逆过来想的话,通过这种方法,我们已经可以确定和某一个Transaction相关联的所有SqlConnection对象。

    下一步是如何通过这些SqlConnection对象找到他们打开着的SqlDataReader对象:

    我们注意到innerConnection 对象里有一个_referenceCollection 成员:

    044821a4  4000f85       14 ...ferenceCollection  0 instance 01ebeda0 _referenceCollection

    我们把它打印下来

    !do 01ebeda0
    Name: System.Data.SqlClient.SqlReferenceCollection
    MethodTable: 04482150
    EEClass: 043b1840
    Size: 16(0x10) bytes
    (C:\Windows\assembly\GAC_32\System.Data\2.0.0.0__b77a5c561934e089\System.Data.dll)
    Fields:
          MT    Field   Offset                 Type VT     Attr    Value Name
    044821f8  4001034        4 ...CollectionEntry[]  0 instance 01ebedb0 _items
    63162b38  4001937        8         System.Int32  1 instance        1 _dataReaderCount

    从中我们可以看出和这个connection 对象相关联的DataReader数量是1。打印_items这个成员,可以看到这个DataReader对象:

    !da 01ebedb0
    Name: System.Data.ProviderBase.DbReferenceCollection+CollectionEntry[]
    MethodTable: 044821f8
    EEClass: 043b1908
    Size: 52(0x34) bytes
    Array: Rank 1, Number of elements 5, Type VALUETYPE
    Element Methodtable: 044822b4
    [0] 01ebedb8
    [1] 01ebedc0
    [2] 01ebedc8
    [3] 01ebedd0
    [4] 01ebedd8

    _items中总共有5个 CollectionEntries。每一个可能或可能没有指向一个打开着的DataReader。由于上诉地址(01ebedb8, 01ebedc0, etc)所指向的都是value type的值,!do对它们不起作用。我们需要借用Visual Studio的Memory dialog来查看这些value:

    0x01ebedb8
    01ebede4 00000001

    0x01ebedc0
    00000000 00000000

    0x01ebedc8
    00000000 00000000

    0x01ebedd0
    00000000 00000000

    0x01ebedd8
    00000000 00000000

    很明显,只有第一个entry 是有效的。根据.NET Reflector的反编译结果,entry的struct 如下定义:

        [StructLayout(LayoutKind.Sequential)]
        private struct CollectionEntry
        {
            private int _tag;
            private WeakReference _weak;
        }

    01ebede4 是 WeakReference的地址. Dump 这个week reference:

    !do 01ebede4
    Name: System.WeakReference
    MethodTable: 6315a09c
    EEClass: 62f1a20c
    Size: 16(0x10) bytes
    (C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
    Fields:
          MT    Field   Offset                 Type VT     Attr    Value Name
    631631b4  40005b4        4        System.IntPtr  1 instance 002112B4 m_handle
    631343b8  40005b5        8       System.Boolean  1 instance        0 m_IsLongReference

    GCHandle 是002112B4。为了找到这个GCHandle的目标对象,我们首先得到被GCHandle指向的值:

    0x002112B4
    01ebed18

    这个值就是目标对象的地址:

    !do 01ebed18
    Name: System.Data.SqlClient.SqlDataReader
    MethodTable: 0447e1bc
    EEClass: 0439c318
    Size: 136(0x88) bytes
    (C:\Windows\assembly\GAC_32\System.Data\2.0.0.0__b77a5c561934e089\System.Data.dll)
    Fields:
          MT    Field   Offset                 Type VT     Attr    Value Name
    63160508  400018a        4        System.Object  0 instance 00000000 __identity
    044814ac  40017d0       20 ...lClient.TdsParser  0 instance 01eb3fbc _parser
    044817d0  40017d1       24 ...ParserStateObject  0 instance 01eb4140 _stateObj
    0447db08  40017d2       28 ...Client.SqlCommand  0 instance 01ebe0cc _command
    0447d75c  40017d3       2c ...ent.SqlConnection  0 instance 01e685c0 _connection
    63162b38  40017d4       58         System.Int32  1 instance     1033 _defaultLCID
    631343b8  40017d5       7c       System.Boolean  1 instance        0 _dataReady
    631343b8  40017d6       7d       System.Boolean  1 instance        0 _haltRead
    631343b8  40017d7       7e       System.Boolean  1 instance        1 _metaDataConsumed
    631343b8  40017d8       7f       System.Boolean  1 instance        0 _browseModeInfoConsumed
    631343b8  40017d9       80       System.Boolean  1 instance        0 _isClosed
    631343b8  40017da       81       System.Boolean  1 instance        1 _isInitialized
    631343b8  40017db       82       System.Boolean  1 instance        1 _hasRows
    048a1740  40017dc       5c         System.Int32  1 instance        0 _altRowStatus
    63162b38  40017dd       60         System.Int32  1 instance       -1 _recordsAffected
    63162b38  40017de       64         System.Int32  1 instance       30 _timeoutSeconds
    048a13e8  40017df       68         System.Int32  1 instance     2008 _typeSystem
    04480e84  40017e0       30 ...ent.SqlStatistics  0 instance 00000000 _statistics
    631340bc  40017e1       34      System.Object[]  0 instance 01ebfc80 _data
    048bed04  40017e2       38 ...t.SqlStreamingXml  0 instance 00000000 _streamingXml
    044822f8  40017e3       3c ...t._SqlMetaDataSet  0 instance 01ebedf4 _metaData
    048be270  40017e4       40 ...DataSetCollection  0 instance 00000000 _altMetaDataSetCollection
    044838e0  40017e5       44 ...e.FieldNameLookup  0 instance 00000000 _fieldNameLookup
    04483bdc  40017e6       6c         System.Int32  1 instance        0 _commandBehavior
    63162b38  40017e8       70         System.Int32  1 instance        1 ObjectID
    048a0c68  40017e9       48 ...tiPartTableName[]  0 instance 00000000 _tableNames
    631608ec  40017ea       4c        System.String  0 instance 00000000 _resetOptionsString
    63162b38  40017eb       74         System.Int32  1 instance        0 _nextColumnDataToRead
    63162b38  40017ec       78         System.Int32  1 instance        0 _nextColumnHeaderToRead
    63162178  40017ed        8         System.Int64  1 instance 0 _columnDataBytesRead
    63162178  40017ee       10         System.Int64  1 instance 0 _columnDataBytesRemaining
    63162178  40017ef       18         System.Int64  1 instance 0 _columnDataCharsRead
    6316151c  40017f0       50        System.Char[]  0 instance 00000000 _columnDataChars
    63160a80  40017f1       54     System.Exception  0 instance 00000000 _rowException
    63162b38  40017e7      884         System.Int32  1   static        1 _objectTypeCount

    啊哈!我们找到了那个SqlDataReader 对象!

    打印出这个SqlDataReader对象相关的Command:

    0447db08  40017d2       28 ...Client.SqlCommand  0 instance 01ebe0cc _command

    !do 01ebe0cc
    Name: System.Data.SqlClient.SqlCommand
    MethodTable: 0447db08
    EEClass: 0439c250
    Size: 132(0x84) bytes
    (C:\Windows\assembly\GAC_32\System.Data\2.0.0.0__b77a5c561934e089\System.Data.dll)
    Fields:
          MT    Field   Offset                 Type VT     Attr    Value Name
    63160508  400018a        4        System.Object  0 instance 00000000 __identity
    654829d8  40008c3        8 ...ponentModel.ISite  0 instance 00000000 site
    6549ccac  40008c4        c ....EventHandlerList  0 instance 00000000 events
    63160508  40008c2      108        System.Object  0   static 01eb07a4 EventDisposed
    63162b38  40016e3       58         System.Int32  1 instance        1 ObjectID
    631608ec  40016e4       10        System.String  0 instance 01e6851c _commandText
    0447e654  40016e5       5c         System.Int32  1 instance        0 _commandType
    63162b38  40016e6       60         System.Int32  1 instance       30 _commandTimeout
    04899120  40016e7       64         System.Int32  1 instance        3 _updatedRowSource
    631343b8  40016e8       78       System.Boolean  1 instance        0 _designTimeInvisible
    048be560  40016e9       14 ...ent.SqlDependency  0 instance 00000000 _sqlDep
    631343b8  40016ea       79       System.Boolean  1 instance        0 _inPrepare
    63162b38  40016eb       68         System.Int32  1 instance       -1 _prepareHandle
    631343b8  40016ec       7a       System.Boolean  1 instance        0 _hiddenPrepare
    0447e870  40016ed       18 ...rameterCollection  0 instance 00000000 _parameters
    0447d75c  40016ee       1c ...ent.SqlConnection  0 instance 01e685c0 _activeConnection
    631343b8  40016ef       7b       System.Boolean  1 instance        0 _dirty
    048a0f28  40016f0       6c         System.Int32  1 instance        0 _execType
    631340bc  40016f1       20      System.Object[]  0 instance 00000000 _rpcArrayOf1
    044822f8  40016f2       24 ...t._SqlMetaDataSet  0 instance 01ebedf4 _cachedMetaData
    04481e50  40016f3       28 ...+CachedAsyncState  0 instance 01ebe74c _cachedAsyncState
    63162b38  40016f4       70         System.Int32  1 instance       -1 _rowsAffected
    048bcd3c  40016f5       2c ...tificationRequest  0 instance 00000000 _notification
    631343b8  40016f6       7c       System.Boolean  1 instance        1 _notificationAutoEnlist
    048bd310  40016f7       30 ...nt.SqlTransaction  0 instance 00000000 _transaction
    04898bac  40016f8       34 ...letedEventHandler  0 instance 00000000 _statementCompletedEventHandler
    044817d0  40016f9       38 ...ParserStateObject  0 instance 00000000 _stateObj
    631343b8  40016fa       7d       System.Boolean  1 instance        0 _pendingCancel
    631343b8  40016fb       7e       System.Boolean  1 instance        0 _batchRPCMode
    00000000  40016fc       3c                       0 instance 00000000 _RPCList
    631340bc  40016fd       40      System.Object[]  0 instance 00000000 _SqlRPCBatchArray
    00000000  40016fe       44                       0 instance 00000000 _parameterCollectionList
    63162b38  40016ff       74         System.Int32  1 instance        0 _currentlyExecutingBatch
    048b2b34  4001700       48 ...miRequestExecutor  0 instance 00000000 _smiRequest
    048b267c  4001701       4c ...Server.SmiContext  0 instance 00000000 _smiRequestContext
    048bd9c8  4001702       50 ...+CommandEventSink  0 instance 00000000 _smiEventSink
    048b27d0  4001703       54 ...DeferedProcessing  0 instance 00000000 _outParamEventSink
    63162b38  40016e2      878         System.Int32  1   static        1 _objectTypeCount
    631340bc  4001704      78c      System.Object[]  0   static 01ebe48c PreKatmaiProcParamsNames
    631340bc  4001705      790      System.Object[]  0   static 01ebe4d8 KatmaiProcParamsNames

    得到command text:

    !do 01e6851c
    Name: System.String
    MethodTable: 631608ec
    EEClass: 62f1d64c
    Size: 92(0x5c) bytes
    (C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
    String: SELECT PersonID, LastName FROM Person
    Fields:
          MT    Field   Offset                 Type VT     Attr    Value Name
    63162b38  4000096        4         System.Int32  1 instance       38 m_arrayLength
    63162b38  4000097        8         System.Int32  1 instance       37 m_stringLength
    631615cc  4000098        c          System.Char  1 instance       53 m_firstChar
    631608ec  4000099       10        System.String  0   shared   static Empty
        >> Domain:Value  003210d0:01de1198 <<
    6316151c  400009a       14        System.Char[]  0   shared   static WhitespaceChars
    >> Domain:Value  003210d0:01de1758 <<

    Command text 是“SELECT PersonID, LastName FROM Person”. 大功告成!

  • 相关阅读:
    java--volatile关键字
    java--线程异常处理器
    java--线程池
    Supervisor安装和使用
    网络协议--HTTP
    1.Nginx简介
    Nginx配置实战
    Redis面试题
    SpringBoot--集成swagger2
    缓存的优缺点
  • 原文地址:https://www.cnblogs.com/Jialiang/p/1500921.html
Copyright © 2020-2023  润新知