• 7905阅读
  • 4回复

数据库 多线程并发访问数据库,容易出错? [复制链接]

上一主题 下一主题
离线foxgod
 

只看楼主 倒序阅读 楼主  发表于: 2014-04-08
来一个socket,建立一个thread,在thread的构造函数里面打开数据,在RUN函数里面执行数据selected 和update,但是有时候总是错误
  1. int main(int argv,char **argc)
  2. {
  3.     QApplication app(argv,argc);
  4.     tcpServer listenSocket;
  5.     if(!listenSocket.listen(QHostAddress::Any,6000))                  //监听本机6000端口,SD专属
  6.         return 0;
  7.     //if(!listenSocket.listen((QHostAddress::Any,8888)))
  8.     return app.exec();
  9. }
  10. //tcpServer.h
  11. #ifndef TCPSERVER_H
  12. #define TCPSERVER_H
  13. #include <QTcpServer>
  14. class tcpServer : public QTcpServer
  15. {
  16.     Q_OBJECT
  17. public:
  18.     tcpServer(QObject *parent = 0);
  19. protected:
  20.     void incomingConnection(int socketDescriptor);
  21. };
  22. #endif // TCPSERVER_H
  23. tcpServer.cpp
  24. #ifndef TCPSERVER_CPP
  25. #define TCPSERVER_CPP
  26. #include <tcpServer.h>
  27. #include <tcpThread.h>
  28. tcpServer::tcpServer(QObject *parent)
  29.     :QTcpServer(parent){
  30. }
  31. void tcpServer::incomingConnection(int socketDescriptor){
  32.     tcpThread *Mythread = new tcpThread(socketDescriptor,this);
  33.     connect(Mythread,SIGNAL(finished()),Mythread,SLOT(deleteLater()));
  34.     Mythread->start();
  35. }
  36. #endif // TCPSERVER_CPP
  37. #ifndef TCPTHREAD_CPP
  38. #define TCPTHREAD_CPP
  39. #include <tcpThread.h>
  40. #include <tcpServer.h>
  41. #include <QDataStream>
  42. #include <QTcpSocket>
  43. #include <QDateTime>
  44. #include <QSqlQuery>
  45. #include <Qtsql>
  46. /**************************构造函数_连接数据库**********************************/
  47. tcpThread::tcpThread(int socketDescriptor, QObject *parent)
  48.     : QThread(parent), socketDescriptor(socketDescriptor){
  49.     if(createConnection())
  50.     {
  51.         qDebug()<<"Mysql Open!";
  52.     }
  53. }
  54. /**************************析构函数_提示线程退出**********************************/
  55. tcpThread::~tcpThread()
  56. {
  57.     emit finished();
  58.     qDebug()<<"A Thread Quit!";
  59. }
  60. /**************************run函数_进行通信及数据库存储**********************************/
  61. void tcpThread ::run(){
  62.     tcpSocket = new QTcpSocket;
  63.     dataTimer = new QTimer;
  64.     cmdTimer = new QTimer;
  65.     tcpSocket->setSocketDescriptor(socketDescriptor);
  66.     dataTimer->start(3500);
  67.     cmdTimer->start(7300);
  68.     sendNum = 1;
  69.     connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readMessage()));
  70.     connect(dataTimer,SIGNAL(timeout()),this,SLOT(sendSearch()),Qt::DirectConnection);//定时器时间到,发送查询命令。Qt::DirectConnection线程内传递消息
  71.     connect(cmdTimer,SIGNAL(timeout()),this,SLOT(sendCommand()),Qt::DirectConnection);//定时器时间到,搜索数据库中是否有需要发出的命令
  72.     connect(tcpSocket,SIGNAL(disconnected()),this,SLOT(quit()));//socket断开连接,线程退出
  73.     qDebug()<<tcpSocket->peerAddress().toString();
  74.     qDebug()<<tcpSocket->peerPort();
  75.     exec();
  76. }
  77. /**************************数据库连接函数**********************************/
  78. bool tcpThread::createConnection(){
  79.     db =new QSqlDatabase;
  80.     if(QSqlDatabase::contains("db_test"))                       //若db_test已经打开,则使用
  81.         *db=QSqlDatabase::database("db_test");
  82.     else
  83.     {
  84.         *db = QSqlDatabase::addDatabase("QMYSQL","db_test");    //若没打开则添加
  85.         db->setDatabaseName("db_test");
  86.     }
  87.     /*
  88.         db->setUserName("xdt");
  89.         db->setPassword("xdt");
  90.         db->setHostName("219.231.143.195");
  91.     */
  92.     db->setUserName("root");
  93.     db->setPassword("shmily504");
  94.     db->setHostName("localhost");
  95.     if (!db->open())
  96.         return false;
  97.     return true;
  98. }
  99. /**************************读取socket传来数据并写入数据库**********************************/
  100. void tcpThread ::readMessage(){
  101.     QByteArray bytesArrived;
  102.     qDebug()<<tcpSocket->bytesAvailable();
  103.     bytesArrived=tcpSocket->readAll();
  104.     QDateTime dateTime;
  105.     QString currentTime=dateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
  106.     qDebug()<<currentTime;
  107.     QSqlQuery mysql(*db);
  108.     if(bytesArrived[0] == 0x02 && bytesArrived[1] == 0xFE && bytesArrived[2] == 0xFE)//26个字节数据
  109.     {
  110.         char deviceType = bytesArrived[3];
  111.         int cdNum = bytesArrived[5];
  112.         qint32 temPerature =bytesArrived[7]*256 + bytesArrived[8];
  113.         char count_H = bytesArrived[11];
  114.         char count_L = bytesArrived[12];
  115.         int deviceState = bytesArrived[13];
  116.         char energyEfficiency =bytesArrived[14];
  117.         qint32 count= count_H*256 + count_L;
  118.         /****************************写原始数据表tb_date_r&&tb_sense*****************/
  119.         QString insertInto_tbSense ="insert into tb_sense(irlast,temp,time) values(?,?,?);";
  120.         mysql.prepare(insertInto_tbSense);
  121.         mysql.addBindValue(count);
  122.         mysql.addBindValue(temPerature);
  123.         mysql.addBindValue(currentTime);
  124.         mysql.exec();
  125.         QString insertInto_tbDateR ="insert into tb_date_r(device_num,cd_num,temp,irlast1,irlast2,device_state,efficiency,time) values(?,?,?,?,?,?,?,?);";
  126.         mysql.prepare(insertInto_tbDateR);
  127.         mysql.addBindValue(deviceType);
  128.         mysql.addBindValue(cdNum);
  129.         mysql.addBindValue(temPerature);
  130.         mysql.addBindValue(count_H);
  131.         mysql.addBindValue(count_L);
  132.         mysql.addBindValue(deviceState);
  133.         mysql.addBindValue(energyEfficiency);
  134.         mysql.addBindValue(currentTime);
  135.         mysql.exec();
  136.         /*******************************更新tb_cddate*****************************/
  137.         if(4 == cdNum)
  138.         {
  139.             QString update_tbCddate;
  140.             update_tbCddate="update tb_cddate set temp=?,device_state=?,time=? where cd_num=4;";
  141.             mysql.prepare(update_tbCddate);
  142.             mysql.addBindValue(temPerature);
  143.             mysql.addBindValue(deviceState);
  144.             mysql.addBindValue(currentTime);
  145.             mysql.exec();
  146.         }
  147.         if(3 == cdNum)
  148.         {
  149.             QString update_tbCddate;
  150.             update_tbCddate="update tb_cddate set temp=?,device_state=?,time=? where cd_num=3;";
  151.             mysql.prepare(update_tbCddate);
  152.             mysql.addBindValue(temPerature);
  153.             mysql.addBindValue(deviceState);
  154.             mysql.addBindValue(currentTime);
  155.             mysql.exec();
  156.         }
  157.         if(2 == cdNum)
  158.         {
  159.             QString update_tbCddate;
  160.             update_tbCddate="update tb_cddate set temp=?,device_state=?,time=? where cd_num=2;";
  161.             mysql.prepare(update_tbCddate);
  162.             mysql.addBindValue(temPerature);
  163.             mysql.addBindValue(deviceState);
  164.             mysql.addBindValue(currentTime);
  165.             mysql.exec();
  166.             if(0x00 == deviceState || 0x04 == deviceState || 0x08 == deviceState || 0x0C == deviceState)
  167.             {
  168.                 QString update_tbLight ="update tb_light set state=2,time=? where id=1";
  169.                 mysql.addBindValue(currentTime);
  170.                 mysql.exec();
  171.             }
  172.             if(0x01 == deviceState || 0x05 == deviceState || 0x09 == deviceState || 0x0D == deviceState)
  173.             {
  174.                 QString update_tbLight ="update tb_light set state=1,time=? where id=1";
  175.                 mysql.addBindValue(currentTime);
  176.                 mysql.exec();
  177.             }
  178.         }
  179.         if(1 == cdNum)
  180.         {
  181.             QString update_tbCddate;
  182.             update_tbCddate="update tb_cddate set temp=?,device_state=?,time=? where cd_num=1;";
  183.             mysql.prepare(update_tbCddate);
  184.             mysql.addBindValue(temPerature);
  185.             mysql.addBindValue(deviceState);
  186.             mysql.addBindValue(currentTime);
  187.             mysql.exec();
  188.             if(0x00 == deviceState || 0x04 == deviceState || 0x08 == deviceState || 0x0C == deviceState)
  189.             {
  190.                 QString update_tbLight ="update tb_aircondition set state=2,efficiency=?,time=? where id=1";
  191.                 mysql.addBindValue(energyEfficiency);
  192.                 mysql.addBindValue(currentTime);
  193.                 mysql.exec();
  194.             }
  195.             if(0x01 == deviceState || 0x05 == deviceState || 0x09 == deviceState || 0x0D == deviceState)
  196.             {
  197.                 QString update_tbLight ="update tb_aircondition set state=1,efficiency=?,time=? where id=1";
  198.                 mysql.addBindValue(energyEfficiency);
  199.                 mysql.addBindValue(currentTime);
  200.                 mysql.exec();
  201.             }
  202.         }
  203.     }
  204.     /**************************若返回的是ACK则更新数据库tb_date_t**********************************/
  205.     if(bytesArrived[0] == 0x04 && bytesArrived[1] == 0x55 && bytesArrived[2] == 0x11)
  206.     {
  207.         uint sum = 0;
  208.         QByteArray temp = bytesArrived.toHex().right(2);
  209.         qDebug()<<temp;
  210.         if(temp[0]<='9')
  211.             sum +=(temp[0]-'0')*16;
  212.         else
  213.             sum +=(temp[0]-'a'+10)*16;
  214.         if(temp[1]<='9')
  215.             sum +=temp[1]-'0';
  216.         else
  217.             sum +=temp[1]-'a'+10;
  218.         uint taskId = sum%256;
  219.         qDebug()<<taskId;
  220.         QString update_tbDateT = "update tb_date_t set state=2,time=? where id=? and state=1";
  221.         qDebug()<<update_tbDateT;
  222.         mysql.prepare(update_tbDateT);
  223.         mysql.addBindValue(currentTime);
  224.         mysql.addBindValue(taskId);
  225.         mysql.exec();
  226.     }
  227. }
  228. /**************************发送查询命令**********************************/
  229. void tcpThread::sendSearch(){
  230.     char block[5];
  231.     char cdNum;
  232.     if(1 == sendNum)
  233.     {
  234.         cdNum =0x01;
  235.         sendNum = 2;
  236.     }
  237.     else if(2 == sendNum)
  238.     {
  239.         cdNum =0x02;
  240.         sendNum = 3;
  241.     }
  242.     else if(3 == sendNum)
  243.     {
  244.         cdNum = 0x03;
  245.         sendNum = 4;
  246.     }
  247.     else if(4 == sendNum)
  248.     {
  249.         cdNum = 0x04;
  250.         sendNum =1;
  251.     }
  252.     block[0]=0x44;
  253.     block[1]=0x11;
  254.     block[2]=0x01;
  255.     block[3]=0x07;
  256.     block[4]=cdNum;
  257.     tcpSocket->write(block,5);
  258. }
  259. /**************************发送控制命令**********************************/
  260. void tcpThread::sendCommand(){
  261.     QSqlQuery send(*db);
  262.     QString haveSendFalse="update tb_date_t set state=3,time= where state=1" ;
  263.     QString currentTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
  264.     send.prepare(haveSendFalse);
  265.     send.addBindValue(currentTime);
  266.     send.exec();
  267.     QString waitSend="select *from tb_date_t where state =0" ;
  268.     send.exec(waitSend);
  269.     while(send.next())
  270.     {
  271.         int i,j=0,t=0;
  272.         QString taskCmd=send.value(2).toString();
  273.         QByteArray sendTask = taskCmd.toLatin1();
  274.         QByteArray sendTaskcmd;
  275.         uchar sendTemp1[10];
  276.         uchar sendTemp2[10];
  277.         qDebug()<<sendTask;
  278.         /**************************STRING_TO_HEX**********************************/
  279.         for(i=0;i<20;i++)
  280.         {
  281.             if(i%2 == 0)
  282.             {
  283.                 switch(sendTask[i])
  284.                 {
  285.                     case 0x30:sendTemp1[j]=0x00;break;
  286.                     case 0x31:sendTemp1[j]=0x10;break;
  287.                     case 0x32:sendTemp1[j]=0x20;break;
  288.                     case 0x33:sendTemp1[j]=0x30;break;
  289.                     case 0x34:sendTemp1[j]=0x40;break;
  290.                     case 0x35:sendTemp1[j]=0x50;break;
  291.                     case 0x36:sendTemp1[j]=0x60;break;
  292.                     case 0x37:sendTemp1[j]=0x70;break;
  293.                     case 0x38:sendTemp1[j]=0x80;break;
  294.                     case 0x39:sendTemp1[j]=0x90;break;
  295.                     case 0x61:sendTemp1[j]=0xa0;break;
  296.                     case 0x62:sendTemp1[j]=0xb0;break;
  297.                     case 0x63:sendTemp1[j]=0xc0;break;
  298.                     case 0x64:sendTemp1[j]=0xd0;break;
  299.                     case 0x65:sendTemp1[j]=0xe0;break;
  300.                     case 0x66:sendTemp1[j]=0xf0;break;
  301.                     default:sendTemp1[j]=0x22;break;
  302.                 }
  303.                 j++;
  304.             }
  305.             else
  306.             {
  307.                 if(sendTask[i] <= 0x39)
  308.                 {
  309.                     sendTemp2[t] = sendTask[i]-0x30;
  310.                 }
  311.                 else
  312.                     sendTemp2[t] = sendTask[i]-0x57;
  313.                 t++;
  314.             }
  315.         }
  316.         for(i=0;i<10;i++)
  317.         {
  318.             sendTaskcmd[i]=sendTemp1[i]+sendTemp2[i];
  319.         }
  320.         tcpSocket->write(sendTaskcmd);
  321.     }
  322. }
  323. #endif // TCPTHREAD_CPP
  324. #ifndef TCPTHREAD_H
  325. #define TCPTHREAD_H
  326. #include <QThread>
  327. #include <QTcpSocket>
  328. #include <QSqlDatabase>
  329. #include <QTimer>
  330. class tcpThread : public QThread{
  331.     Q_OBJECT
  332. public:
  333.     void run();
  334.     tcpThread(int socketDescriptor,  QObject *parent);
  335.     ~tcpThread();
  336.     bool createConnection();
  337. public slots:
  338.     void sendSearch();
  339.     void readMessage();
  340.     void sendCommand();
  341. private:
  342.     int socketDescriptor;
  343.     QTcpSocket* tcpSocket;
  344.     QTimer* dataTimer;
  345.     QTimer* cmdTimer;
  346.     int sendNum;
  347.     QSqlDatabase* db;
  348. };
  349. #endif // TCPTHREAD_H

可是多个客户端一起并发时候,容易产生错误。
离线songzhao831

只看该作者 1楼 发表于: 2014-06-17
我也遇到了相同的错误, 多线线程并发访问的时候, 就出现没有响应的情况. 有大神出来解释下吗???????
离线songzhao831

只看该作者 2楼 发表于: 2014-06-17
楼主试过我Qmutex吗?
离线liudianwu

只看该作者 3楼 发表于: 2015-11-22
我也是遇到这种情况,主线程创建的addDatabase,子线程使用查询增删改,偶尔出现QSqlError(2006, "QMYSQL: 不能提交事务", "MySQL server has gone away")的情况导致后面没数据了,后面在子线程中加了QMutex保护,就好了!
欢迎关注微信公众号:Qt实战/Qt入门和进阶(各种开源作品、经验整理、项目实战技巧,专注Qt/C++软件开发,视频监控、物联网、工业控制、嵌入式软件、国产化系统应用软件开发) QQ:517216493  WX:feiyangqingyun  QQ群:751439350
离线XChinux

只看该作者 4楼 发表于: 2015-11-22
Qt文档中不是讲了么,不要跨线程使用QSqlDatabase连接,即在哪个线程里创建的连接,就只在该线程中使用这个连接,不要在其他线程中使用该连接。

解决办法有两个,一是每个线程单独创建自己的Sql的连接使用,二是对该数据库操作都放到一个单独线程中。
二笔 openSUSE Vim N9 BB10 XChinux@163.com 网易博客 腾讯微博
承接C++/Qt、Qt UI界面、PHP及预算报销系统开发业务
快速回复
限100 字节
 
上一个 下一个