程序有两个线程,每个线程都有lock table 语句,但是两个线程仍然能访问相同的字段,而且在程序运行过程中,通过mysql控制台仍然能够update该字段。但是两个线程运行结束(该程序的运行窗口没有关闭),此时通过mysql控制台进行update,则阻塞,只有当关闭该程序运行窗口时,阻塞解除,可以进行update了。不知道是怎么回事?难道在多线程中,不能用lock table语句锁表?

解决方案 »

  1.   

    多线程可以LOCK。
    估计是你的线程的代码没写正确。
      

  2.   

    你的程序操作,产生一个SESSION连接,SESSION1;
    MYSQL命令行再操作,产生SESSION2S1对表进行LOCK TABLE的时候,在表上加的是X锁,级别最高。这时候S2想在UPDATE的时候再加X锁,就必须等待前面的X锁释放。才能加上X锁。在你的程序进行LOCK TABLE后,再执行UNLOCK TABLES,那么就会释放X锁。
      

  3.   

    谢谢ls两位,我改了源码,用两个不同的连接,其中线程1用lock table语句,但是线程2仍然能够update,不知道为什么?源码如下:
    #include <windows.h>
    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <CString>
    #include <sql.h>
    #include <sqlext.h>
    #include <odbcss.h>
    using namespace std;CRITICAL_SECTION Section;
    SQLHENV henv1 = 0;
    SQLHENV henv2= 0;
    SQLHDBC hdbc1 = 0;    
    SQLHDBC hdbc2 = 0;   
    int ConnectDB(SQLHENV &henv,SQLHDBC &hdbc)
    {
    RETCODE retcode;                                      //signed short
    retcode = SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv);//申请环境句柄
    retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER);
    char szDSN[10] = "test_db";                         //一个合法的DSN   Name   
    char szUID[5] = "root";                               //用户名
    char szAuthStr[5] = "root";   
    retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);//申请连接句柄
    retcode = SQLConnect(hdbc, (SQLCHAR *)szDSN, (SWORD)strlen(szDSN),   
    (SQLCHAR *)szUID, (SWORD)strlen(szUID),   
    (SQLCHAR *)szAuthStr,(SWORD)strlen(szAuthStr));  if((retcode != SQL_SUCCESS)&&(retcode != SQL_SUCCESS_WITH_INFO))   
    printf("Connection Error\n"); 
    else 
    printf("Connection Successfully\n");
    return retcode;
    }
    DWORD WINAPI ThreadOne(LPVOID param); 
    DWORD WINAPI ThreadTwo(LPVOID param); int main(int argc, char* argv[])
    {
    if(ConnectDB(henv1,hdbc1))
    cout<<"Connect failed!"<<endl;
    else
    cout<<"Connect successful!"<<endl; if(ConnectDB(henv2,hdbc2))
    cout<<"Connect failed!"<<endl;
    else
    cout<<"Connect successful!"<<endl; HANDLE handl1;
    HANDLE handl2;
    handl1=CreateThread(NULL,0,ThreadOne,NULL,0,NULL);
    handl2=CreateThread(NULL,0,ThreadTwo,NULL,0,NULL);
    CloseHandle(handl1);
    CloseHandle(handl2); InitializeCriticalSection(&Section);
    Sleep(40000);
    DeleteCriticalSection(&Section); getchar();
    return 0;
    } DWORD WINAPI ThreadOne(LPVOID param){
    SQLHSTMT hstmt = 0;
    RETCODE retcode;
    RETCODE retcode1;
    SQLTCHAR sql[60]={0};
    SQLTCHAR sql1[60]={0};
    SQLINTEGER number;
    SQLINTEGER cbKey;
    while(TRUE)
    {
    strcpy((char *)sql,"lock tables test write");
    retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt);
    retcode = SQLExecDirect(hstmt,sql,SQL_NTS); strcpy((char *)sql,"select number from test where ID = '1002'");
    retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt);
    retcode = SQLExecDirect(hstmt,sql,SQL_NTS);
    retcode = SQLFetch(hstmt);
    SQLGetData(hstmt,1,SQL_C_SLONG,&number,0,&cbKey); if (number>0)
    { strcpy((char *)sql,"select number from test where ID = '1002'");
    retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt);
    retcode = SQLExecDirect(hstmt,sql,SQL_NTS);
    retcode = SQLFetch(hstmt);
    SQLGetData(hstmt,1,SQL_C_SLONG,&number,0,&cbKey);
    Sleep(10); cout<<"thread2:"<<number<<endl; strcpy((char *)sql,"update test set number=number-1 where ID = '1002'");
    retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt);
    retcode = SQLExecDirect(hstmt,sql,SQL_NTS);

    }
    else
    break;
    }
    cout<<"thread 2 is running"<<endl; SQLFreeHandle(SQL_HANDLE_STMT,hstmt);
    return 0;
    }DWORD WINAPI ThreadTwo(LPVOID param){
    SQLHSTMT hstmt = 0;
    RETCODE retcode;
    SQLTCHAR sql[60]={0};
    SQLINTEGER number;
    SQLINTEGER cbKey;
    while(TRUE)
    {
    strcpy((char *)sql,"select number from test where ID = '1002'");
    retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc2, &hstmt);
    retcode = SQLExecDirect(hstmt,sql,SQL_NTS);
    retcode = SQLFetch(hstmt);
    SQLGetData(hstmt,1,SQL_C_SLONG,&number,0,&cbKey); if (number>0)
    {
    strcpy((char *)sql,"select number from test where ID = '1002'");
    retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc2, &hstmt);
    retcode = SQLExecDirect(hstmt,sql,SQL_NTS);
    retcode = SQLFetch(hstmt);
    SQLGetData(hstmt,1,SQL_C_SLONG,&number,0,&cbKey);
    Sleep(10);
    cout<<"thread3:"<<number<<endl; strcpy((char *)sql,"update test set number=number-1 where ID = '1002'");
    retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc2, &hstmt);
    retcode = SQLExecDirect(hstmt,sql,SQL_NTS);
    }
    else
    break;
    }
    SQLFreeHandle(SQL_HANDLE_STMT,hstmt);
    return 0;
    }
      

  4.   

    我的程序SESSION1进行lock table时加了锁(线程1),不过mysql控制台SESSION2仍然能够update,说明我的线程1实际上并没有锁表,不知道是什么缘故?(线程1没有用unlock table语句)
      

  5.   

    未必是线程1先执行. 跟线程调度有关系。
    你要在线程2上也加lock table,那样才有效果。
      

  6.   

    谢谢,我在线程2加了lock table之后,在程序运行过程中,mysql控制台仍然能够update该数据表~
    在多线程中,不同的线程都修改同一个表,如何处理锁表呢?怎么测试呢?
      

  7.   

    我重新看了一下你的代码,似乎问题也不大,
    有两个问题:
    1. 每次获取连接之后,立即执行set AUTOCOMMIT = 0 (必须这样,否则调了lock ...之后,会立即释放锁)
    2. 在进行了1之后,lock之后,线程退出之前,别忘了调用unlock多线程是个细心活儿:-)
      

  8.   

    O(∩_∩)O~ 
    set AUTOCOMMIT = 0 这个是做什么的的?
    AUTOCOMMIT 这个变量是什么啊?
    谢谢喽~
      

  9.   

    你把set autocommit=0,当sql语句执行就行。
    它的意思是禁止自动提交。
    否则lock table write自动提交完,锁也就放掉了。
      

  10.   

    O(∩_∩)O~谢谢了~现在锁成功了~不过又出现了新问题,while循环每次只执行一次了(我加了unlock table 语句)~哎~我再看看吧~
      

  11.   

    都将number-1,要看你number的初值是多少了
      

  12.   

    number的初值是200.
    不过我的表类型是MyISAM类型,好像AUTOCOMMIT 变量在处理MyISAM表类型时不起作用。
    其实我的主要目的就是多线程访问数据库(同一个表)时,①当一个线程正在写入数据时,其他线程不能写,也不能读。②当一个线程正在读入数据时,其他线程不能写,但能够读。
    不知道这方面应该怎么做,或者有没有什么例子或者看看哪方面的书籍
    O(∩_∩)O~我刚刚接触数据库~
      

  13.   

    这样子,那建议你不要用MyISAM引擎,进而使用InnoDB引擎。 
      

  14.   

    我们开始时用InnoDB引擎,不用由于数据量较大,使用InnoDB引擎时更新数据速度较慢,改用MyISAM引擎后,速度提高了。不过由于MyISAM引擎不支持事务等操作,所以锁表方面我也不太清楚应该怎么弄?呵呵~
      

  15.   

    理解你的场景。
    这时,你不要借助于sql语句中的lock table之类的,
    你要自己实现一套读写锁。建议有空看看Unix网络编程第二卷,--进程间通信