再问lock table锁表问题,麻烦大家帮忙看一下~

Ying_加油 2010-12-03 04:19:33
程序有两个线程,每个线程都有lock table 语句,但是两个线程仍然能访问相同的字段,而且在程序运行过程中,通过mysql控制台仍然能够update该字段。但是两个线程运行结束(该程序的运行窗口没有关闭),此时通过mysql控制台进行update,则阻塞,只有当关闭该程序运行窗口时,阻塞解除,可以进行update了。

不知道是怎么回事?难道在多线程中,不能用lock table语句锁表?

...全文
293 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
Ying_加油 2010-12-08
  • 打赏
  • 举报
回复
O(∩_∩)O~总之谢谢你了~一直在跟帖~我去看看进程间通信的内容~再次感谢~
[Quote=引用 16 楼 iihero 的回复:]

引用 15 楼 fishneu 的回复:

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

引用 14 楼 iihero 的回复:

引用 13 楼 fishneu 的回复:

number的初值是200.
不过我……
[/Quote]
iihero 2010-12-06
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 fishneu 的回复:]

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

引用 14 楼 iihero 的回复:

引用 13 楼 fishneu 的回复:

number的初值是200.
不过我的表类型是MyISAM类型,好像AUTOCOMM……
[/Quote]
理解你的场景。
这时,你不要借助于sql语句中的lock table之类的,
你要自己实现一套读写锁。

建议有空看看Unix网络编程第二卷,--进程间通信

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

[Quote=引用 14 楼 iihero 的回复:]

引用 13 楼 fishneu 的回复:

number的初值是200.
不过我的表类型是MyISAM类型,好像AUTOCOMMIT 变量在处理MyISAM表类型时不起作用。
其实我的主要目的就是多线程访问数据库(同一个表)时,①当一个线程正在写入数据时,其他线程不能写,也不能读。②当一个线程正在读入数据时,其他线程不能写,但能够读。
不知道这方面应该怎么做,或者有没有什么例子或者看看……
[/Quote]
iihero 2010-12-06
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 fishneu 的回复:]

number的初值是200.
不过我的表类型是MyISAM类型,好像AUTOCOMMIT 变量在处理MyISAM表类型时不起作用。
其实我的主要目的就是多线程访问数据库(同一个表)时,①当一个线程正在写入数据时,其他线程不能写,也不能读。②当一个线程正在读入数据时,其他线程不能写,但能够读。
不知道这方面应该怎么做,或者有没有什么例子或者看看哪方面的书籍
O(∩_∩)O~我刚刚接触数据库……
[/Quote]
这样子,那建议你不要用MyISAM引擎,进而使用InnoDB引擎。
Ying_加油 2010-12-06
  • 打赏
  • 举报
回复
number的初值是200.
不过我的表类型是MyISAM类型,好像AUTOCOMMIT 变量在处理MyISAM表类型时不起作用。
其实我的主要目的就是多线程访问数据库(同一个表)时,①当一个线程正在写入数据时,其他线程不能写,也不能读。②当一个线程正在读入数据时,其他线程不能写,但能够读。
不知道这方面应该怎么做,或者有没有什么例子或者看看哪方面的书籍
O(∩_∩)O~我刚刚接触数据库~

[Quote=引用 12 楼 iihero 的回复:]

都将number-1,要看你number的初值是多少了
[/Quote]
iihero 2010-12-05
  • 打赏
  • 举报
回复
都将number-1,要看你number的初值是多少了
iihero 2010-12-04
  • 打赏
  • 举报
回复
未必是线程1先执行. 跟线程调度有关系。
你要在线程2上也加lock table,那样才有效果。
Ying_加油 2010-12-04
  • 打赏
  • 举报
回复
O(∩_∩)O~谢谢了~现在锁成功了~不过又出现了新问题,while循环每次只执行一次了(我加了unlock table 语句)~哎~我再看看吧~
[Quote=引用 10 楼 iihero 的回复:]

引用 9 楼 fishneu 的回复:

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

引用 8 楼 iihero 的回复:

我重新看了一下你的代码,似乎问题也不大,
有两个问题:
1. 每次获取连接之后,立即执行set AUTOCOMMIT = 0 (必须这样,否则调了lock ...之……
[/Quote]
iihero 2010-12-04
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 fishneu 的回复:]

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

引用 8 楼 iihero 的回复:

我重新看了一下你的代码,似乎问题也不大,
有两个问题:
1. 每次获取连接之后,立即执行set AUTOCOMMIT = 0 (必须这样,否则调了lock ...之后,会立即释放锁)
2. 在进行了1之后,……
[/Quote]
你把set autocommit=0,当sql语句执行就行。
它的意思是禁止自动提交。
否则lock table write自动提交完,锁也就放掉了。
Ying_加油 2010-12-04
  • 打赏
  • 举报
回复
O(∩_∩)O~
set AUTOCOMMIT = 0 这个是做什么的的?
AUTOCOMMIT 这个变量是什么啊?
谢谢喽~

[Quote=引用 8 楼 iihero 的回复:]

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

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

多线程是个细心活儿:-)
Ying_加油 2010-12-04
  • 打赏
  • 举报
回复
谢谢,我在线程2加了lock table之后,在程序运行过程中,mysql控制台仍然能够update该数据表~
在多线程中,不同的线程都修改同一个表,如何处理锁表呢?怎么测试呢?

[Quote=引用 6 楼 iihero 的回复:]

未必是线程1先执行. 跟线程调度有关系。
你要在线程2上也加lock table,那样才有效果。
[/Quote]
Ying_加油 2010-12-03
  • 打赏
  • 举报
回复
我的程序SESSION1进行lock table时加了锁(线程1),不过mysql控制台SESSION2仍然能够update,说明我的线程1实际上并没有锁表,不知道是什么缘故?(线程1没有用unlock table语句)


[Quote=引用 3 楼 zuoxingyu 的回复:]
你的程序操作,产生一个SESSION连接,SESSION1;
MYSQL命令行再操作,产生SESSION2

S1对表进行LOCK TABLE的时候,在表上加的是X锁,级别最高。这时候S2想在UPDATE的时候再加X锁,就必须等待前面的X锁释放。才能加上X锁。

在你的程序进行LOCK TABLE后,再执行UNLOCK TABLES,那么就会释放X锁。
[/Quote]
Ying_加油 2010-12-03
  • 打赏
  • 举报
回复
谢谢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(§ion);
Sleep(40000);
DeleteCriticalSection(§ion);

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;
}
zuoxingyu 2010-12-03
  • 打赏
  • 举报
回复
你的程序操作,产生一个SESSION连接,SESSION1;
MYSQL命令行再操作,产生SESSION2

S1对表进行LOCK TABLE的时候,在表上加的是X锁,级别最高。这时候S2想在UPDATE的时候再加X锁,就必须等待前面的X锁释放。才能加上X锁。

在你的程序进行LOCK TABLE后,再执行UNLOCK TABLES,那么就会释放X锁。
fxs_2008 2010-12-03
  • 打赏
  • 举报
回复
两个线程,用不同的连接
ACMAIN_CHM 2010-12-03
  • 打赏
  • 举报
回复
多线程可以LOCK。
估计是你的线程的代码没写正确。

57,062

社区成员

发帖
与我相关
我的任务
社区描述
MySQL相关内容讨论专区
社区管理员
  • MySQL
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧