基于 Qt 文档:
只能在创建它的线程内使用连接。不支持在线程之间移动连接或从不同线程创建查询。
困扰我的问题是,当我复制构建数据库实例时会发生什么。例如,这是主线程中的代码:
int main(int argc, char** argv) {
...
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", "DB1");
db.setHostName("localhost");
...
这是工作线程中的连接:
void MyThread::run() {
QSqlDatabase db(QSqlDatabase::database("DB1"));
if (db.open()) {
...
}
这个线程安全吗?通常,这样的操作在 C++ 中是安全的,但由于 QT 使用隐式共享和线程关联,我不再确定。
他们说:一个连接只能在创建它的线程中使用,但这是什么意思?是创建连接的QSqlDatabase::addDatabase 点还是调用open()函数时的实际位置。
更新:
在 Laszlo Papp 的回答之后,并最终查看了 Qt 源代码,我必须说 Qt 这部分的设计在我看来是有缺陷的。
如果我理解正确,QSqlDatabase 在后台使用隐式共享,但不幸的是它不是真正的隐式共享,因为 QSqlDatabase 实例的复制构造函数不会在需要时创建共享数据的新实例。更糟糕的是,您不能创建临时连接,而是必须使用静态方法 addDatabase/removeDatabase,在这种情况下,您必须同步线程以避免名称冲突。
这当然使得在 QtConcurrent 中使用 QSqlDatabase 变得非常困难,特别是如果连接应该深埋在某些抽象后面。由于我们不知道代码将在哪个线程上运行,因此我们无法在两个调用之间保持连接打开。如果我们想生成动态数量的任务,我们需要确保任务不使用相同的数据库名称。
所有这些让我想知道设计目标以及隐式共享是否适合这种特殊情况。恕我直言,更好的解决方案是让复制构造函数真正完成它并为您制作连接副本。那些不想拥有私有/临时副本的人仍然可以使用 addDatebase/removeDatabase,在这种情况下,需要修改方法 database() 以返回引用。