您的位置:首页 > 数据库

QSqlDatabase 使用小结,解决部分数据库操作导致程序崩溃的办法

2010-08-04 16:18 609 查看
这两天都在为 QSqlDatabase 类头疼 因为涉及多个连接 连接到同一个数据库 而又没有对各个连接设置名称 网上大部分简易教程都是采用默认数据库连接名称 这样就会导致在对其中一个数据库连接进行操作时 影响到其它数据连接的操作(其实本质上他们是同一个连接) 因为我采用多文档窗体在各个窗体处理不同的数据连接 所以移除或者改变一个连接 也会导致其它连接跟着受到影响 直接导致了程序假死崩溃

本来毫无头绪 不知道个所以然 参照前辈的文章来写程序 也没翻看相应的文档解释 导致头大了两天 唉

现在贴出文档的部分信息

QSqlDatabase QSqlDatabase::addDatabase ( const QString & type, const QString & connectionName = QLatin1String( defaultConnection ) )   [static]
Adds a database to the list of database connections using the driver type and the connection name connectionName. If there already exists a database connection called connectionName, that connection is removed.

The database connection is referred to by connectionName. The newly added database connection is returned.

If type is not available or could not be loaded, isValid() returns false.

If connectionName is not specified, the new connection becomes the default connection for the application, and subsequent calls to database() without the connection name argument will return the default connection. If a connectionName is provided here, use database(connectionName) to retrieve the connection.

Warning: If you add a connection with the same name as an existing connection, the new connection replaces the old one. If you call this function more than once without specifying connectionName, the default connection will be the one replaced.

Before using the connection, it must be initialized. e.g., call some or all of setDatabaseName(), setUserName(), setPassword(), setHostName(), setPort(), and setConnectOptions(), and, finally, open().

Note: This function is thread-safe.

See also database(), removeDatabase(), and Threads and the SQL Module.


以上是addDatabase的说明 第一个是连接数据库的类型 第二个是连接名称 如果我们直接采用

dbconn = QSqlDatabase::addDatabase("QSQLITE);
dbconn.setDatabaseName("./DbfInUse/"+SqliteDB::DbName);


这样的形式进行设置实例的话 那么此时连接的名称是qt的默认数据连接名称 当然这就是导致多个连接实例操作同一个数据库出错的根源所在

所以我们必须采用下面这样的形式进行连接数据库

dbconn = QSqlDatabase::addDatabase("QSQLITE",currentConnName);
dbconn.setDatabaseName("./DbfInUse/"+SqliteDB::DbName);


currentConnName必须与其它实例不相同 不然也会导致多个连接操作出错

警告信息已经说的很清楚

Warning: If you add a connection with the same name as an existing connection, the new connection replaces the old one. If you call this function more than once without specifying connectionName, the default connection will be the one replaced.


如果使用的连接名称已经存在 则先前那个连接将被替换掉。

再看看removedatabase

void QSqlDatabase::removeDatabase ( const QString & connectionName )   [static]
Removes the database connection connectionName from the list of database connections.

Warning: There should be no open queries on the database connection when this function is called, otherwise a resource leak will occur.

Example:

// WRONG
QSqlDatabase db = QSqlDatabase::database("sales");
QSqlQuery query("SELECT NAME, DOB FROM EMPLOYEES", db);
QSqlDatabase::removeDatabase("sales"); // will output a warning

// "db" is now a dangling invalid database connection,
// "query" contains an invalid result set
The correct way to do it:

{
QSqlDatabase db = QSqlDatabase::database("sales");
QSqlQuery query("SELECT NAME, DOB FROM EMPLOYEES", db);
}
// Both "db" and "query" are destroyed because they are out of scope
QSqlDatabase::removeDatabase("sales"); // correct
To remove the default connection, which may have been created with a call to addDatabase() not specifying a connection name, you can retrieve the default connection name by calling connectionName() on the database returned by database(). Note that if a default database hasn't been created an invalid database will be returned.

Note: This function is thread-safe.

See also database(), connectionName(), and Threads and the SQL Module.


这里removedatabase也必须传入相应要移除的连接名称 如果有先前多个连接采用默认的数据连接名称 或者是相同的名称 不管你移除哪个连接(实际上是同一个) 都会导致程序出错

移除前 需要将该连接上取得的数据 资源释放掉 不然将可能导致内存泄漏

非默认连接名称的QSqlDatabase实例 在使用query 或者model进行操作的时候 实例化query或者model都必须设置使用的QSqldatabase 其实就是设置连接名称

形如如下所示

QSqlQuery query(dbconn);
query.exec(sql_string);
return query;


或者
model= new QSqlTableModel(this,db->dbconn);
model->setTable(tr("文字表"));
model->select();
ui->tableView->setModel(model);
ui->tableView->hideColumn(0);


model= new QSqlQueryModel(this);
model->setQuery(tr("select 客户编号 from 客户表 "),db->dbconn);


其实也是一知半解 下面贴一下改造过的数据库连接类

h文件

#ifndef SQLITEDB_H
#define SQLITEDB_H
#include <QString>
#include <QtSql>
class SqliteDB
{
public:
SqliteDB(QString connName);
~SqliteDB();
static void setDbName(QString name);
static QString getDbName();
QStringList findDbfiles();
bool connDb();
QSqlQuery search(QString sql_string);
void closeDb();
QSqlQuery query;
QSqlDatabase dbconn;
QString currentConnName;
private:
static QString DbName;

};

#endif // SQLITEDB_H


cpp文件

#include "sqlitedb.h"
#include <QDir>
#include <QtSql>
#include <QString>
#include <QMessageBox>
QString SqliteDB::DbName="";
SqliteDB::SqliteDB(QString connName)
{
currentConnName=connName;
}
SqliteDB::~SqliteDB()
{
if(dbconn.isOpen()==true)
{
dbconn.close();
}
QSqlDatabase::removeDatabase(dbconn.connectionName());
}
void SqliteDB::setDbName(QString name)
{
SqliteDB::DbName=name;
}
QString SqliteDB::getDbName()
{
return DbName;
}
QStringList SqliteDB::findDbfiles()
{
QDir dir;
dir.setPath("./DbfInUse");
dir.setFilter(QDir::Files | QDir::Hidden);
dir.setSorting(QDir::Name);
QStringList names = dir.entryList();
QStringList newnames;
newnames=names.filter(".dbf");
return newnames;
}
bool SqliteDB::connDb()
{
if(!dbconn.isValid())
{
dbconn = QSqlDatabase::addDatabase("QSQLITE",currentConnName); dbconn.setDatabaseName("./DbfInUse/"+SqliteDB::DbName);
}
if(dbconn.isOpen()==true)
{
return true;
}
else
{
if(!dbconn.open())
{
return false;
}
else
{
return true;
}
}
}
QSqlQuery SqliteDB::search(QString sql_string)
{
QSqlQuery query(dbconn); query.exec(sql_string); return query;
}
void SqliteDB::closeDb()
{
if(dbconn.isOpen()==true)
{
dbconn.close();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐