マルチスレッドアクセスデータベース問題

7026 ワード

最近マルチスレッドのリモートアップグレードソフトを作って、完成したら対応するテストプログラムを使ってテストします。スレッドが複数あると必ず崩壊します。すべてのデータベース処理を全部削除したら、同時に何百スレッドも実行できます。原因は自分でシングルモードを採用して、各スレッドの中でTcpServerに信号を送ります。serverでは、単一スレッドでSqlite Toolの単一の例のオペレーティングデータベースを呼び出します。これはより安全で効率的であるべきだと思いましたが、今はマルチスレッドでスタティック関数を加えるべきです。
2018/3/23更新:
    1.ワンケースモードは使用しないでください。マルチスレッドアクセスの対象はピットです。Javaの下の接続プールの管理対象は一例ですが、接続プールのオブジェクトは複数です。静的関数で大丈夫です。
#include "dbtool.h"
#include 
#include 
#include 
#include 
#include 

QMutex DBTool::mutex4Thread;
DBTool::DBTool()
{
    qDebug()<
使う時はロックをかけます。二つのQSql Databaseの対象は部分的にして、removeしなければなりません。
void TcpThread::db_progress(double progress)
{
    QMutexLocker locker(&DBTool::mutex4Thread);
    QString progressStr=QString::number(progress*100,'f',2)+"%";
    {
        QSqlDatabase db=DBTool::getConnection();
        QSqlQuery query(db);
        query.prepare("UPDATE table_all set progress = :progress WHERE id LIKE :id");
        query.bindValue(":progress",progressStr);
        query.bindValue(":id",_id);
        if(!query.exec())
        {
            qDebug()<
    2.データベース画面を更新し、Query操作をサブスレッド内に入れて、メインスレッドで時間をつぶしないようにしてください。
#include "sql4ui.h"
#include 
#include 
#include "tool/dbtool.h"
#include 
#include 
#include 
#include "global.h"
#include 

Sql4ui::Sql4ui(QObject *obj, int request, int page_num, QString filter_sql, QString query_filter) : QRunnable()
{
    _obj=obj;
    _request=request;
    _page_num=page_num;
    _filter_sql=filter_sql;
    _query_filter=query_filter;
}

Sql4ui::~Sql4ui()
{
}

void Sql4ui::run()
{
    if(_request==0) //    
    {
        refresh_table();
    }
    else if(_request==1)    //        
    {
        query_count();
    }
}

void Sql4ui::refresh_table()
{
    {
        QSqlDatabase db=DBTool::getConnection();
        int count=0;
        //QString cells[ROW_OF_TABLE][COLUMN_OF_TABLE];
        //  []  resize
        QVector> cells(ROW_OF_TABLE);
        for(int i=0;i vec(COLUMN_OF_TABLE);
            cells[i]=vec;
        }
        {
            QMutexLocker locker(&DBTool::mutex4Thread);
            //    where_sql     count
            QSqlQuery query1("SELECT count(*) FROM table_all"+_filter_sql,db);
            if(query1.next())
            {
                count=query1.value(0).toInt();
            }
            QSqlQuery query(db);
            int start=(_page_num-1)*ROW_OF_TABLE;
            if(_filter_sql!="")
            {
                query.prepare("SELECT * FROM table_all "+_filter_sql+" ORDER BY id");
                if(query.exec())
                {
                    int rowIndex=0;
                    if(query.seek(start))
                    {
                        bool is_next_ok=true;
                        while(is_next_ok&&rowIndex :start AND id <= :end");
                query.bindValue(":start",start);
                query.bindValue(":end",end);
                if(query.exec())
                {
                    int rowIndex=0;
                    while(query.next())
                    {
                        cells[rowIndex][0]=query.value("id").toString();
                        cells[rowIndex][1]=query.value("SA").toString();
                        cells[rowIndex][2]=query.value("status").toString();
                        cells[rowIndex][3]=query.value("progress").toString();
                        cells[rowIndex][4]=query.value("error").toString();
                        cells[rowIndex][5]=query.value("datetime").toString();
                        rowIndex++;
                    }
                }
            }
        }
        QMetaObject::invokeMethod(_obj,"invokeTable",Qt::QueuedConnection,Q_ARG(int,count),Q_ARG(QVector>,cells));
    }
    DBTool::removeConnection();
}

void Sql4ui::query_count()
{
    {
        QSqlDatabase db=DBTool::getConnection();
        int count=0;
        {
            QMutexLocker locker(&DBTool::mutex4Thread);
            QSqlQuery query(db);
            query.prepare("SELECT count(*) FROM table_all "+_query_filter);
            if(query.exec())
            {
                if(query.next())
                {
                    count=query.value(0).toInt();
                }
            }
        }
        QMetaObject::invokeMethod(_obj,"invokeQueryCount",Qt::QueuedConnection,Q_ARG(int,count));
    }
    DBTool::removeConnection();
}
参照
    
QtデータベースはQSql Database:addDatabase()によって生成されたQSql Databaseはその作成スレッドでしか使用できません。マルチスレッドで接続を共有したり、他のスレッドでqueryを作成したりするのはサポートされていません。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15bool  openDatabase(){    QSqlDatabase db;    QString connectionName = "sqlite";    db = QSqlDatabase::addDatabase("QSQLITE", connectionName);    db.setDatabaseName("/jyxtec.db");    if  (db.open())        return  true;    else     return  false;}void  testQuery(){    QSqlQuery query(QSqlDatabase::database("sqlite"));    query.exec("SELECT * from t_test");   }ここのtestQuery()はマルチスレッドの呼び出しをサポートしていません。OpenDatabase()を起動するスレッドでのみ使用できます。そうでないと、エラーが発生しやすいです。解決方法は2つあります。1)testQueryを呼び出すスレッドごとに、異なるconnection Nameを作成するQSql DatabaseなどのスレッドAQSql Databaseを作成します。QSqlQuery query(QSql Database::database(“A”);スレッドBQSql Database:addDatabase(「QSQLITE」「B」);QSqlQuery query(QSql Database::database(「B」);
2)データベーススレッド池を実現し、Nつの異なるconnectionation Nameを作成するQSQSql Database。すべてのqueryコマンドをこのスレッド池に置いて処理する。
 
ここでネットの大牛に感謝します。
参照先:
http://blog.csdn.net/goldenhawking/article/details/10811409
http://blog.chinaunix.net/uid-20680966-id-4779621.html
他の二つのパッケージ
http://blog.csdn.net/wsj18808050/article/details/44891715
http://blog.csdn.net/lwwl12/article/details/76124210