2016-04-04 3 views
1

Ich habe eine Anwendung erstellt, die SQLDriverConnect aufruft, um eine Verbindung zu einer MS SQL Server-Datenbank namens "MyDB" herzustellen. Nach einigen Aktionen ruft es SQLDisconnect.Aber dann kann SSMS 'MyDB' nicht löschen. Dies bedeutet, dass einige Ressourcen nicht ordnungsgemäß geschlossen werden. Nur nach dem Beenden des Prozesses, löscht SSMS es (, d. H. das OS veröffentlicht sie) und alle SQLHENV und SQLHDBC werden ordnungsgemäß freigegeben. -Code unten:ODBC-Objekte korrekt freigeben?

SMARTHSTMT::~SMARTHSTMT() 
{ 
    if (!m_hstmt) return; 
    SQLFreeStmt(m_hstmt, SQL_CLOSE); 
    SQLFreeStmt(m_hstmt, SQL_UNBIND); 
    SQLFreeStmt(m_hstmt, SQL_RESET_PARAMS); 
    SQLFreeHandle(SQL_HANDLE_STMT, m_hstmt); 
    m_hstmt = nullptr; 
}; 

Wie kann ich feststellen, welches Objekt nicht freigegeben? Gibt es noch weitere Überlegungen, die ich anstellen sollte? Jede Idee oder Hilfe wird geschätzt. Edit: Code zum Freischalten:

void AConnection::uDisconnect() 
{ 
    if (m_hdbc) 
    { 
     SQLDisconnect(m_hdbc); 
     SQLFreeHandle(SQL_HANDLE_DBC, m_hdbc); 
     m_hdbc = nullptr; 
    } 
    if (m_henv) 
    { 
     SQLFreeHandle(SQL_HANDLE_ENV, m_henv); 
     m_henv = nullptr; 
    } 
} 
+0

Was ist das Ergebnis von SQLDisconnect? Ihr Code postete nur das Freigeben des Anweisungshandles, was ist mit dem Verbindungs- und Umgebungshandle? – erg

+0

Sie werden mit SQLFreeHandle freigegeben. Ich habe nur den Code zum Zerstören von Aussagen gepostet, weil Aussagen weit verbreitet sind und man sie leicht vergessen kann. –

+0

Wenn Sie ein Verbindungs-Handle freigeben, sollten Sie einen SQLERROR als Rückgabewert erhalten, wenn offene Anweisungs-Handles von diesem Verbindungs-Handle stammen, nicht? – erg

Antwort

0

können Sie überprüfen, ob SQLDisconnect() kehrt SQL_ERROR. Wenn dies der Fall ist, ist eine Anweisung möglicherweise noch offen oder eine Transaktion (wie Sie festgestellt haben) ist noch offen.

Transaktion in ODBC Handhabung ist (vereinfacht) wie folgt aus:

standardmäßig Auto-commit aktiviert ist. Alles startet eine neue Transaktion und wenn die Anweisung erfolgreich ist, wird die Transaktion festgeschrieben. Wenn Sie den Commit-Modus nicht geändert haben, ist es für mich verwirrend, dass eine Transaktion noch offen ist.

Wenn Sie deaktiviert autocommit haben, müssen Sie manuell SQLEndTrans(...) rufen alle laufenden Transaktion zu begehen oder Rollback. Soweit ich weiß, gibt es in ODBC keine Möglichkeit, den Treiber abzufragen, wenn eine Transaktion noch offen ist.

Wie Sie die Anrufe SQLEndTrans() erwähnen, ich denke, Sie haben bereits deaktiviert auto-commit. Wenn ich mir meine Quellen anschaue, sehe ich, dass ich immer einen Rollback mache, bevor ich einen Verbindungs-Handle schließe - vielleicht erinnere ich mich wegen des gleichen Problems nicht genau (sein alter Code).

Wie auch immer, wenn Sie den manuellen Modus begehen aktiviert haben, würde ich nur empfehlen, einen Rollback zu tun, bevor die Verbindung Griff zu schließen. Vielleicht gäbe es Tools auf der SQL-Server-Seite, um weitere Einzelheiten zu analysieren, was damals genau offen ist ..

Sehen Sie hier für weitere Informationen: https://msdn.microsoft.com/en-us/library/ms131281.aspx

+0

Danke. Ihre Antwort ist sehr klar und nützlich. Wie Sie vermuten, deaktiviere ich die automatische Festschreibung und rufe SQLEndTrans zum Festschreiben oder Rollback auf. und ich entschied mich, auch vor SQLDisconnect zu rollen. Dies ist meine letzte Frage: Warum Anweisungen wie SQLColumns, SQLTables, SQLStatistics eine Transaktion starten? –

+0

@MohamadrezaAbdolahzadeh: Ich habe keine Ahnung, warum die Katalog-Funktionen eine Transaktion starten. Ich denke, ich habe mit dem gleichen Problem gekämpft und keine brauchbare Lösung gefunden. Vielleicht wäre es das wert, als eigenständige Frage hinzuzufügen. – erg