2011-10-06 20 views
26

mi sono confuso con il manuale, dovrei lavorare in questo modo:Qual è il modo corretto di QSqlDatabase e QSqlQuery?

{ 
QSqlDatabase db = QSqlDatabase::addDatabase (...); 
QSqlQuery query (db); 
query.exec (...); 
} 

QSqlDatabase::removeDatabase (...); 

Come il documento sottolinea, query o db verrà suddivisa automaticamente. Ma è così efficiente?

Beh, se io Caché db all'interno di una classe, come il seguente:

class Dummy { 
    Dummy() { 
    db = QSqlDatabase::addDatabase (...); 
    } 
    ~Dummy() { 
    db.close(); 
    } 

    bool run() { 
    QSqlQuery query (db); 
    bool retval = query.exec (...); 
    blabla ... 
    } 

    private: 
    QSqlDatabase db; 
}; 

A volte ho potuto vedere gli avvertimenti come:

QSqlDatabasePrivate::removeDatabase: connection 'BLABLA' is still in use, all queries will cease to work. 

Anche se non ho chiamato run().

risposta

41

Quando si crea un oggetto QSqlDatabase con addDatabase o quando si chiama removeDatabase, si stanno semplicemente associando o dissociare una tupla (driver, hostname: port, nome del database, nome utente/password) a un nome (o al default nome della connessione se non si specifica un nome di connessione).
Il driver SQL viene istanziato, ma il database verrà aperto solo quando si chiama QSqlDatabase::open.

Quel nome di connessione è definito a livello di applicazione. Pertanto, se si chiama addDatabase in ciascuno degli oggetti che lo utilizzano, si modificano tutti gli oggetti QSqlDatabase che utilizzano lo stesso nome di connessione e invalidano tutte le query attive su di essi.

Il primo esempio di codice che hai citato mostra come dissociare correttamente il nome della connessione, assicurando che:

  • tutti QSqlQuery sono staccati dal QSqlDatabase prima di chiudere il database chiamando QSqlQuery::finish(), che è automatico quando il QSqlQuery oggetto va fuori del campo di applicazione,
  • tutte QSqlDatabase con lo stesso nome di connessione sono close() d quando si chiama QSqlDatabase::removeDatabase (close() è anche chiamato automaticamente quando l'oggetto QSqlDatabase passa mai di sc OPE).

Quando si crea il QSqlDatabase, a seconda se si desidera che la connessione rimanere aperto per tutta la durata di applicazione (1) o solo quando necessario (2), è possibile:

  1. mantenere un singolo QSqlDatabase istanza in una singola classe (ad esempio, nella tua finestra principale) e usarla in altri oggetti che ne hanno bisogno passando il QSqlDatabase direttamente o semplicemente il nome della connessione che si passa a QSqlDatabase::database per ottenere l'istanza QSqlDatabase indietro. utilizza QHash per recuperare un QSqlDatabase dal suo nome, quindi è probabilmente trascurabilmente più lento che passare l'oggetto QSqlDatabase direttamente tra oggetti e funzioni e, se si utilizza la connessione predefinita, non è nemmeno necessario passare nulla, basta chiamare QSqlDatabase::database() senza alcun parametro.

    // In an object that has the same lifetime as your application 
    // (or as a global variable, since it has almost the same goal here) 
    QSqlDatabase db; 
    
    // In the constructor or initialization function of that object  
    db = QSqlDatabase::addDatabase("QSQLDRIVER", "connection-name"); 
    db.setHostname(...); 
    // ... 
    if(!this->db.open()) // open it and keep it opened 
    { 
        // Error handling... 
    } 
    
    // -------- 
    // Anywhere you need it, you can use the "global" db object 
    // or get the database connection from the connection name   
    QSqlDatabase db = QSqlDatabase::database("connection-name"); 
    QSqlQuery query(db);    
    
  2. configurare il QSqlDatabase volta, aprirlo per verificare che i parametri siano corretti, e l'istanza fosso. Il nome della connessione, sarà ancora accessibile ovunque, ma il database dovrà essere riaperto:

    { 
        // Allocated on the stack 
        QSqlDatabase db = QSqlDatabase::addDatabase("QSQLDRIVER", "connection-name"); 
        db.setHostname(...); 
        // ... 
        if(!this->db.open()) // test the connection 
        { 
         // Error handling 
        } 
    // db is closed when it goes out of scope 
    } 
    
    { 
        // Same thing as for (1), but by default database() opens 
        // the connection if it isn't already opened 
        QSqlDatabase db = QSqlDatabase::database("connection-name"); 
        QSqlQuery query(db); 
    
    // if there is no other connection open with that connection name, 
    // the connection is closed when db goes out of scope 
    } 
    

    In tal caso, si noti che non si deve chiudere il database in modo esplicito, perché si può avere più oggetti utilizzando lo stesso connessione al database in un modo rientranti (ad esempio, se una funzione utilizza la connessione e chiama B che utilizza anche la connessione. Se B chiude la connessione prima di restituire il controllo ad A, la connessione verrà chiusa anche per A, che è probabilmente un brutta cosa).

+0

ho avuto questo problema, dopo aver fanno di questo adattamento sono riuscito a chiudere il database chiamando '' QSqlDatabase :: removeDatabase (QSqlDatabase :: database ("Nome database"); '' –

3

QSqlDatabase e QSqlQuery sono involucri leggeri attorno alle implementazioni concrete, quindi il tuo primo esempio va bene. Se si fornisce un nome quando si aggiunge la connessione o si utilizza il database predefinito, la semplice scrittura di "QSqlDatabase db (name)" fornisce l'oggetto del database con un sovraccarico molto ridotto.

removeDatabase equivale a chiudere il file (per sqlite) o la connessione (per ODBC/MySql/Postgres), quindi in genere ciò che si farebbe alla chiusura del programma. Come dice l'avvertimento, è necessario assicurarsi che tutti gli oggetti di database e di query che si riferiscono a quel database siano già stati distrutti o che possano accadere cose brutte.

0

trovo che le istruzioni devono essere eseguiti esattamente nell'ordine in cui si è al di sotto, altrimenti si hanno problemi, sia con la connessione al database o la query. Funziona in Qt5.

QSqlQueryModel *model = new QSqlQueryModel; 
db = QSqlDatabase::addDatabase("QSQLITE"); 
db.setDatabaseName(fileName); 

if (db.isValid()) 
{ 
    db.open(); 
    if (db.isOpen()) 
    { 
     QSqlQuery searchQuery(db); 
     searchQuery.prepare("SELECT * FROM myTable"); 
     searchQuery.exec(); 
     if(searchQuery.isActive()) 
     { 
      model->setQuery(searchQuery); 
      sui->DBDisplay->setModel(model); 
      db.close(); 
     } else { 
      qDebug() << "query is not active"; 
     } 
    } else { 
     qDebug() << "DB is not open"; 
    } 
} else { 
    qDebug() << "DB is not valid"; 
} 
Problemi correlati