關於qt中QSqlDatabase使用:如果使用單一的數據庫,以sqlite為例:
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
QString dbFileName = "xxx.db";
db.setDatabaseName(dbFileName );
if (db.isOpen()) {
db.open();
}
... //db operator
但是當一個程序中需要使用兩個數據庫(比如軟件更新時拷貝原先數據庫中的內容等),則需要操作兩個數據庫,如果只是相似地使用:
QSqlDatabase db1 = QSqlDatabase::addDatabase("QSQLITE");
QString dbFileName1 = "xxx.db";
db1.setDatabaseName(dbFileName1);
if (db1.isOpen()) {
db1.open();
}
... //db operator
此時往往會出現以下警告,導致數據庫執行失敗:
QSqlDatabasePrivate::removeDatabase: connection 'qt_sql_default_connection' is still in use, all queries will cease to work.
QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed.
閱讀qt源代碼可以了解到:
static QSqlDatabase addDatabase(const QString& type,
const QString& connectionName = QLatin1String(defaultConnection))
其中關於defaultConnection: QT_STATIC_CONST_IMPL
char *QSqlDatabase::defaultConnection = "qt_sql_default_connection";
QSqlDatabase QSqlDatabase::addDatabase(QSqlDriver* driver, const QString&
connectionName)
{
QSqlDatabase db(driver);
QSqlDatabasePrivate::addDatabase(db, connectionName);
return db;
}
void QSqlDatabasePrivate::addDatabase(const QSqlDatabase &db, const QString &name)
{
QConnectionDict *dict = dbDict();
Q_ASSERT(dict);
QWriteLocker locker(&dict->lock);
if (dict->contains(name)) {
invalidateDb(dict->take(name), name);
qWarning("QSqlDatabasePrivate::addDatabase: duplicate connection name '%s', old "
"connection removed.", name.toLocal8Bit().data());
}
dict->insert(name, db);
db.d->connName = name;
}
觀察QSqlDatabase::addDatabase中還有一個默認參數,其實這才是數據庫真實的名字,而setDatabaseName只是設置數據庫的路徑(別被表面意思忽悠了);從代碼中可以看到addDatabase最終調用其私有對象的addDatabase,最終將數據庫的名字insert到了QConnectionDict。
以下,看到QConnectionDict,大家一定就會恍然大悟,其實,這就是一個HASH Table,形成一個數據庫名字與內容的映射,最終在調用調用
QSqlDatabase QSqlDatabasePrivate::database(const QString& name, bool open)時將用到這個表。
class QConnectionDict: public QHash<QString, QSqlDatabase>
{
public:
inline bool contains_ts(const QString &key)
{
QReadLocker locker(&lock);
return contains(key);
}
inline QStringList keys_ts() const
{
QReadLocker locker(&lock);
return keys();
}
mutable QReadWriteLock lock;
};
看到這里大家應該能看出以上報錯的原因了吧:由於addDatabase(),默認打開數據庫並設置數據庫名字為qt_sql_default_connection,所以當兩次調用addDatabase(),將會提醒你qt_sql_default_connection已經打開,將關閉原先的數據庫,重新建一個qt_sql_default_connection。
還有一點就是QSqlDatabasePrivate::open()函數調用,
Returns true if the database connection is currently open; otherwise returns false.
之前想當然的以為文件不存在也會報出錯,但后來實踐證明,open()函數和c中打開文件一樣,如果文件不存在將會建立一個該文件,而不會報錯。
https://www.xuebuyuan.com/3227745.html
