Programm hängt während Datenbankabfrage



  • Hi zusammen,

    ich schreibe gerade ein Programm, dass mit OLE DB auf eine Oracle DB zugreift und dort eine Stored Procedure aufruft.

    Mein Problem ist nun, dass während dieses Aufrufs mein Programm hängt, bis die Funktion 'zurückkehrt'.

    Hier mal meinen Aufruf:

    CCommand<CAccessor<CDBAccessor>,CNoRowset> command;
    //alle Parameter zurücksetzen
    command.ClearRecord();
    
    //StoredProcedure aufrufen - hier hängt die Anwendung bis die Procedure fertig ist
    HRESULT hr = command.Open(*m_session, _T("{ CALL FIND_ARTIKEL (?, ?, ?) }"));
    if(FAILED(hr)) 
       AfxMessageBox("StoredProcedure nicht ausführbar!");
    else 
       AfxMessageBox("Erfolgreich ausgeführt!");
    command.Close();
    

    Ich hab auch schon versucht die Datenbankabfrage aus einem Workerthread heraus zu starten und bin leider gescheitert, da er zur DB keine Verbindung bekommt.

    Weiß jemand Rat?
    Vielen Dank für Tipps!

    Grüße
    Mav

    BTW: Ist dass das Richtige Forum für sowas?



  • Wenn du Code ausführst der lange dauert dann wird die Messageschleife nicht ausgeführt.
    Es kann immer nur eine Zeile im Code ausgeführt werden und das ist in deinem Fall nunmal der DB-Code.
    Du wirst also nicht um Threads herum kommen.

    Verwende die Klasse CWinThread.



  • Ich hab den Hinweis aufgenommen und mir ne Thread-Klasse angelegt (wie in der FAQ beschrieben) und rufe nun folgendermaßen auf:

    //Starte den Thread...
    m_StatusThread = (CStatusThread*) 
         AfxBeginThread(RUNTIME_CLASS(CStatusThread), NULL, 0, CREATE_SUSPENDED);
    m_StatusThread->SetOwner(this);
    m_StatusThread->ResumeThread();
    
    //...und dann die Datenbankabfrage...
    CCommand<CAccessor<CDBAccessor>,CNoRowset> command; 
    //alle Parameter zurücksetzen 
    command.ClearRecord(); 
    
    //StoredProcedure aufrufen - hier hängt die Anwendung bis die Procedure fertig ist 
    HRESULT hr = command.Open(*m_session, _T("{ CALL FIND_ARTIKEL (?, ?, ?) }")); 
    if(FAILED(hr))  
       AfxMessageBox("StoredProcedure nicht ausführbar!"); 
    else  
       AfxMessageBox("Erfolgreich ausgeführt!"); 
    command.Close();
    

    In die Funktion CStatusThread::Run() hab ich nur ne MessageBox in ner Schleife drin.

    Jetzt ist es allerdings so, dass er die MessageBoxaufrufe erst bringt, wenn die DB-Abfrage abgelaufen ist - also bleibt das Programm quasi immernoch stehen.

    Ich habs auch schon andersherum probiert, dass ich die DB-Abfrage in die Run() reinschreibe:

    //Vorbereitung
    class CTestView
    {
      CDataSource* m_db;
      CDBPropSet*	dbinit;
      CSession* m_session;
      [...]
    }
    
    //Datenbank beim Start der Anwendung initialisieren
    void CTestView::OnInitialUpdate()
    {
      //DB initialisieren:
      HRESULT		hr;
    
      //Open DataSource
      m_db = new CDataSource();
    
      //Eigenschaften festlegen
      dbinit = new CDBPropSet(DBPROPSET_DBINIT);
      dbinit->AddProperty(DBPROP_INIT_LCID, (long)1031);
      dbinit->AddProperty(DBPROP_INIT_PROMPT, (short)4);
      dbinit->AddProperty(DBPROP_INIT_PROVIDERSTRING, OLESTR(""));
      hr = m_db->Open(_T("OraOLEDB.Oracle.1"), dbinit);
    
      //Start Session
      m_session = new CSession();
      hr = m_session->Open(*m_db);
    }
    
    //...und wenn der Thread gestartet wird...
    void CStatusThread::Run()
    {
      CCommand<CAccessor<CDBAccessor>,CNoRowset> command; 
      //alle Parameter zurücksetzen 
      command.ClearRecord(); 
    
      HRESULT hr = command.Open(*((CTestView*) m_pOwner)->m_session, _T("{ CALL FIND_ARTIKEL (?, ?, ?) }")); 
      if(FAILED(hr))  
         AfxMessageBox("StoredProcedure nicht ausführbar!"); 
      else  
         AfxMessageBox("Erfolgreich ausgeführt!"); 
      command.Close();
    }
    

    Hier bringt er mir eine Unbehandelte Ausnahme (Access Violation) beim Aufruf von command.open(...).



  • ist ja auch klar das die MessageBox erst nach der Datenbankabfrage kommt da ein Code Zeile für Zeile abgearbeitet wird.

    Dein Programm bleibt aber nicht hängen da die Messageschleife in einem anderen Thread (HauptDlgThread) abgearbeitet wird und die Oberfläche noch reagiert.



  • Hmm, ich schätze ich hab das mit den Threads noch nicht ganz verstanden.

    Angenommen ich definiere meine CStatusThread::Run() so:

    int CStatusThread::Run()
    {
      int i = 0;
    
      while(i < 100)
      {
        AfxMessageBox("Thread");
        i++;
      }
      return 0;
    }
    

    Wenn ich jetzt aus meiner Hauptanwendung den Thread starte und anschließend meinen DB-Aufruf (ebenfalls aus der Hauptanwendung) starte müsste ich doch während der DB-Abruf abläuft, 100 MessageBoxs zu sehen bekommen - da ja der Thread selbst weiter läuft - oder?



  • So, warum eine AccessViolation in der zweiten Variante hervorgerufen wird (wenn der DB-Abruf im Thread realisiert ist) hab ich jetzt.
    --> OLE DB muss in jedem Thread initialisiert werden. 😡

    Für alle die's interessiert:

    Damit man also Threads nutzen kann, muss in der InitInstance() der Thread-Klasse die Funktion CoInitialize(NULL) aufgerufen werden, entsprechend in der ExitInstance() dann CoUninitialize(). 😃

    Könnte dann so aussehen:

    BOOL CStatusThread::InitInstance()
    {
    	HRESULT hRes = CoInitialize(NULL);
    	if(FAILED(hRes)) return FALSE;
    
    	return TRUE;
    }
    
    int CStatusThread::ExitInstance()
    {
    	CoUninitialize();
    
    	return CWinThread::ExitInstance();
    }
    

    @Unix-Tom: Danke für Deine Unterstützung und vor allem dem Hinweis auf die CWinThread-Klasse!!! 🙂
    Mit Worker-Threads hab ich's net hinbekommen...


Anmelden zum Antworten