2017-05-18 2 views
1

QSqlDatabase를 사용하는 프로젝트를 수행하고 있습니다. 그리고 지금은 QtConcurrent (QFuture)를 사용하여 SQL 명령을 실행하고 있습니다.QSqlDatabase 풀 (QThreadPool)

지금 당장은 QFuture를 사용하여 실행되는 모든 새 명령이 내 MySQL 서버에 대한 새로운 QSqlDatabase 연결을 만듭니다. 나는 Mysql 서버에 대한 새로운 연결이 악수에 대한 처벌을받을 것이라고 믿는다. 그래서 풀 QSqlDatabase를 만들 계획을 가지고 있으며, 문서 QSqlDatabase를 작성한 스레드 만 사용할 수 있습니다.

그래서 내 생각은 QMap 풀을 만드는 것입니다. int는 스레드 ID이고 QString은 연결 이름입니다. 따라서 qfuture를 사용하여 스레드 풀에서 스레드를 시작하려면 QMap 풀에서 연결 이름을 가져 와서이 QSqlDatabase가 이미 서버에 연결된 QSqlDatabase를 가져옵니다.

샘플 코드 :

//this is static variable 
QMap<int, QString> pool; 
..... 

//At the beginning of sql command to execute 
if(pool.contains((int)QThread::currentThreadId()) { 
    db = QSqlDatabase::database(pool[(int)QThread::currentThreadId()]); 
} else { 
    QString key = "someunique" + QString::number((int)QThread::currentThreadId()); 
    db = QSqlDatabase::add(key) 
    ... // some Qsql connection code 
    pool.insert((int)QThread::currentThreadId(), key); 
} 

은 어쩌면 위의 내 코드가 작동

,하지만 내가 물어보고 싶은를 : 내 생각 일 것입니까? 아니면 QSqlDatabase에 대해 뭔가를 놓쳤는가?

답변

0

첫째, 스레드 자체의 QObject 속성으로 연결을 추가하면 작동하지 않는 아이디어입니다. QObject 속성 시스템이 스레드로부터 안전하지 않기 때문에 작동하지 않습니다.

간단한 아이디어는 QThreadStorage을 사용하여 스레드 로컬 저장소에 데이터베이스 연결을 저장하는 것입니다.

QThreadStorage<QSqlDatabase> connections; 

QSqlDatabase newConnection(); 

QSqlDatabase getConnection() { 
    auto & connection = connections.localData(); 
    if (! connection.isValid()) 
    connection = newConnection(); 
    return connection; 
} 

당신의 생각은 오래 당신이 풀에 동시 액세스를 직렬화 같이 작동합니다 : 풀에서 스레드가 사라질 때이 자동으로 배치됩니다. 또한 스레드가 완료 될 때 연결이 정리되도록해야합니다. id을 사용하는 대신 QThread 포인터를 직접 사용할 수도 있습니다. 문자열 키로 연결을 참조 할 필요가 없습니다. 값이므로 직접 저장할 수 있습니다. QSqlDatabase은 파일 핸들과 마찬가지로 핸들입니다.

QReadWriteLock poolLock; 
QMap<QThread*, QSqlDatabase> pool; 

struct ConnectionDropper : public QObject { 
    void drop() { 
    QWriteLocker writeLock{&poolLock}; 
    pool.remove(qobject_cast<QThread*>(sender())); 
    } 
} 
Q_GLOBAL_STATIC(Dropper, dropper); 

QSqlDatabase newConnection(); 

QSqlDatabase getConnection() { 
    auto thread = QThread::currentThread(); 
    QReadLocker readLock{&poolLock}; 
    auto it = std::find(pool.begin(), pool.end(), thread); 
    if (it != pool.end()) 
    return it.value(); 
    readLock.unlock(); 
    // connecting can take some time, so don't lock the pool while it happens 
    auto conn = newConnection(); 
    // Unique connections to functors are not implemented, thus we need an object. 
    QObject::connect(thread, &QThread::finished, &*dropper, 
    &ConnectionDropper::drop, Qt::DirectConnection | Qt::UniqueConnection); 
    QWriteLocker writeLock{&poolLock}; 
    pool.insert(thread, conn); 
    return conn; 
} 
+0

안녕하세요 @ 쿠바, Btw 어느 쪽이 가장 좋습니까? QThreadStorage를 사용하거나 풀 (하단)을 사용합니까? – Apin

+0

@Apin 나는 항상 더 적은 것이 더 좋을 때를 선호하므로 그 답은 분명해야한다. 나는 풀 솔루션이 포함되어있어 제대로 돌아가는 것이 더 까다 롭다는 것을 입증한다. –