关于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中打开文件一样,如果文件不存在将会建立一个该文件,而不会报错。