2017-10-28 37 views
1

因此,即時消息有關於qt和sql命令的一個問題,我已經坐了幾個小時,但更容易發生,而不是簡單。Qt在不在主類中的函數中執行SQL命令

我試圖有多種形式,在每一個我連接數據庫,並執行一些操作。這工作正常,但是 - 只要我將所述操作移動到說按鈕按下功能,我收到數據庫未打開錯誤。我不關閉這個類中的任何地方的數據庫,但錯誤仍然存​​在。

我已經看到了問題的一部分是以下錯誤:

QSqlDatabasePrivate :: removeDatabase:連接「qt_sql_default_connection」仍然在使用,所有的查詢將停止工作。

QSqlDatabasePrivate :: addDatabase:重複的連接名稱'qt_sql_default_connection',舊的連接被刪除。

當我重新構造代碼(用於調試)並刪除第一種形式的連接時,錯誤消失,並且數據庫在第二類函數中保持打開狀態。 下面,次級類

HomeScreen::HomeScreen(QWidget *parent):QWidget(parent),ui(newUi::HomeScreen){ 
    ui->setupUi(this); 
    connect(ui->btnInclogShow,SIGNAL(pressed()),this,SLOT(ShowLogs())); 
    dbe = QSqlDatabase::addDatabase("QMYSQL"); 
    dbe.setDatabaseName("securitydb"); 
    dbe.setUserName("root"); 
    dbe.setPassword(""); 
    dbe.open(); 
    if(dbe.open()){ 
     qDebug() << "Database is open in main part"; 
    } 
    else{qDebug() << "Database is closed";} 
} 

HomeScreen::~HomeScreen() 
{ 
    delete ui; 
} 

void HomeScreen::ShowLogs() 
{ 
    qDebug() << "Showlogs pressed"; 
    if(dbe.open()){ 
     qDebug() << "Database is open"; 
    } 
    else{qDebug() << "Database is closed";} 
} 

下面初級班

MainWindow::MainWindow(QWidget *parent) : 
    QMainWindow(parent), 
    ui(new Ui::MainWindow) 
{ 

    ui->setupUi(this); 

    db = QSqlDatabase::addDatabase("QMYSQL"); 
    db.setDatabaseName("securitydb"); 
    db.setUserName("root"); 
    db.setPassword(""); 
    db.open(); 

    connect(ui->btnLogin,SIGNAL(pressed()),this,SLOT(LoginClicked())); 
    if(db.open()){ 
     qDebug() << "Database is open"; 
    } 
    else{qDebug() << "Database is closed";} 
} 

MainWindow::~MainWindow() 
{ 
    delete ui; 
    db.close(); 
    db.removeDatabase("securitydb"); 
} 

void MainWindow::LoginClicked() 
{ 
    qDebug() << "pressed"; 
    this->destroy(); 
    HomeScreengui->show(); 
} 

作爲一種嘗試,以減輕這個問題,我宣佈在第二類的新數據庫變量,這沒有奏效。 任何幫助,將不勝感激!

+0

你說你不關閉數據庫,但你在析構函數中做這件事。沒有必要在代碼的每個部分打開數據庫,只需在main.cpp中執行它,QSqlDatabase有一個全局實例。你叫什麼摧毀? – eyllanesc

+0

儘管析構函數,我仍然收到錯誤,謝謝你的評論,但我會嘗試在主要開放! – Renierler

回答

0

首先,你必須瞭解QSqlDatabase是如何工作的。

Qt管理數據庫連接列表。每個連接都由一個唯一的名稱標識。您可以添加新連接,檢索現有連接或從列表中刪除連接。這是使用函數完成:

  • QSqlDatabase::addDatabase()
  • QSqlDatabase::database()
  • QSqlDatabase::removeDatabase()

同樣的QSqlDatabase幾個實例可以參考相同的連接。因此,在以下代碼db0db1中引用相同的連接。

QSqlDatabase db0 = QSqlDatabase::addDatabase("MYSQL", "foo"); 
QSqlDatabase db1 = QSqlDatabase::database("foo"); 

此外,在需要連接名稱的函數中,可以省略名稱。 Qt會將其作爲默認數據庫處理。如果只有一個連接,這可能很方便。

請注意,Qt使用「qt_sql_default_connection」作爲默認數據庫的名稱。因此,例如QSqlDatabase::database()QSqlDatabase::database("qt_sql_default_connection")返回相同的連接。


現在看看你的代碼。您可以在兩個構造函數中調用QSqlDatabase::addDatabase("QMYSQL");。第二個調用將在由Qt管理的連接列表中添加一個新連接,並刪除以前的連接。這就是爲什麼你有以下警告:

QSqlDatabasePrivate :: addDatabase:重複的連接名 'qt_sql_default_connection',舊的連接刪除。

而且因爲拆除連接在使用,你會得到一個額外的警告:

QSqlDatabasePrivate :: removeDatabase:連接 「qt_sql_default_connection」仍然在使用,所有的查詢將不再 工作。

要解決此問題,您只需撥打QSqlDatabase::addDatabase()一次。這可以通過讓你的一個類負責處理數據庫連接來完成,其他類只會調用QSqlDatabase::database(),但是你必須確保你只有這個類的一個實例。或者你可以在每一個類撥打電話到QSqlDatabase::addDatabase(),但只有當數據庫中不存在(見QSqlDatabase::contains()):

// Add a default databse only if it does not exist. 
if (!QSqlDatabase::contains()) 
{ 
    QSqlDatabase::addDatabase("MYSQL"); 
} 

而且你行db.removeDatabase("securitydb");是完全錯誤的。 QSqlDatabase::removeDatabase()是一個靜態函數,參數是連接名稱,而不是數據庫名稱。它應該是:

QSqlDatabase::removeDatabase(); // Remove the default database 

所以,你的代碼應該是這樣的:

HomeScreen::HomeScreen(QWidget *parent):QWidget(parent),ui(newUi::HomeScreen) 
{ 
    ui->setupUi(this); 
    connect(ui->btnInclogShow, &QPushButton::pressed, this, &HomeScreen::ShowLogs); 

    if (QSqlDatabase::contains()) 
     dbe = QSqlDatabase::addDatabase("QMYSQL"); 
    else 
     dbe = QSqlDatabase::database(); 

    dbe.setDatabaseName("securitydb"); 
    dbe.setUserName("root"); 
    dbe.setPassword(""); 

    if(dbe.open()){ 
     qDebug() << "Database is open in main part"; 
    } 
    else{ 
     qDebug() << dbe.lastError().text(); 
    } 
} 

MainWindow::MainWindow(QWidget *parent) : 
    QMainWindow(parent), 
    ui(new Ui::MainWindow) 
{ 

    ui->setupUi(this); 

    if (QSqlDatabase::contains()) 
     db = QSqlDatabase::addDatabase("QMYSQL"); 
    else 
     db = QSqlDatabase::database(); 

    db.setDatabaseName("securitydb"); 
    db.setUserName("root"); 
    db.setPassword(""); 

    connect(ui->btnLogin, &QPushButton::pressed,this, &MainWindow::LoginClicked); 
    if(db.open()){ 
     qDebug() << "Database is open"; 
    } 
    else{ 
     qDebug() << dbe.lastError().text(); 
    } 
} 

MainWindow::~MainWindow() 
{ 
    delete ui; 
    // WARNING: If HomeScreen is still using the connection the next 2 lines will leak resources and make HomeScreen lose its connection. 
    db.close(); 
    QSqlDatabase::removeDatabase(); 
} 
+0

非常感謝您的好評! @Benjamin T – Renierler

0

每次調用addDatabase同一基礎數據庫的時候,請確保您設置一個唯一的連接名稱:

if (QSqlDatabase::contains("foo")) { 
    QSqlDatabase::removeDatabase("foo"); 
} 
db = QSqlDatabase::addDatabase("QMYSQL", "foo"); 
db.setDatabaseName("securitydb"); 

注意,連接名字不一樣的數據庫名。所以在這裏你打開多個獨立的連接到同一個數據庫。

如果您沒有明確設置連接名稱,Qt將使用默認值。此默認連接名稱將用於對基礎數據庫的所有訪問。因此,如果您在以默認連接名稱打開的數據庫上調用close(),則它將有效關閉使用該默認名稱打開的所有數據庫對象的