在线程执行数据库查询强行终止查询并释放线程?(100分)

  • 主题发起人 主题发起人 lxggc
  • 开始时间 开始时间
在线程执行数据库查询强行终止查询并释放线程
这样做是不合理的,因为程序对数据库的操作是两部分,一部分是程序,当程序把
查询命令传给数据库服务器后,程序便无法控制服务器,如程序强行终止,服务器端
任久在执行。如果服务器端查询没有结束,程序又启动线程,将出错。
 
假如用户想取消一个耗时很长的查询那该咋办?
 
我没有碰到查数据库的问题,但是碰到过线程需要做长时间操作的问题,你试试先suspend,
然后再free看看。
 
利用线程在后台执行查询
这样用户就感觉不到在查询数据库
 
希望能有人回答,急需解决。
 
对不起,随手写的过程中,几个地方写错了。上面代码已经作了更正。:-)
不过直接终止后,应该不会发生 OnTerminate 事件了吧。没测试,自己看看吧。
如果数据库支持 abort 方法,最好调用一次后再强行终止线程。
 
不行啊.分出错的啊.
 
对不起,对不起。看下面吧:
========================================================================
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TQueryThread = class(TThread)
protected
procedure Execute;
override;
procedure Updata;
end;

TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
Stop:Boolean;
QT:TQueryThread;
QT_Handle:THandle;
ExitCode:DWord;
procedure TerminateIt(Sender: TObject);
procedure ThreadKill;
procedure ThreadStart;
public
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.ThreadStart;
begin
Stop:=True;
qt:=TQueryThread.Create(True);
QT_Handle:=qt.Handle;
with qtdo
begin
FreeOnTerminate:=True;
OnTerminate:=TerminateIt;
// 测试时可以用这个过程查看
Resume;
end;
end;

procedure TQueryThread.Updata;
begin
// 画 Form 的颜色
if Form1.Color=clBlack then
Form1.Color:=clBtnFace
else
Form1.Color:=clBlack;
end;

procedure TForm1.TerminateIt;
begin
// 自然终止的话,显示消息
MessageBox(0,'线程终止了','信息',MB_OK);
end;

// 强行终止线程
procedure TForm1.ThreadKill;
begin
TerminateThread(QT_Handle,ExitCode);
end;

procedure TQueryThread.Execute;
begin
while Form1.Stopdo
begin
// 这里执行一个查询,在发出查询后,等待返回 (实际上就是休眠)
Synchronize(Updata);
// 随便执行一个死循环,这里是画 Form 颜色
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
// 线程启动
ThreadStart;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
// 自然终止线程
Stop:=false;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
// 强行终止线程
ThreadKill;
end;
end.
======================================================================
以后我一定仔细检查自己写的代码 :-) ,呵呵。
 
可以直接终止这个线程的。以下是示意代码:
type
TQueryThread = class(TThread)
protected
procedure Execute;
override;
end;
var // 全局变量 ( 示例 )
QT:TQueryThread;
QT_Handle:THandle;
ExitCode:DWord;
// 实际的线程代码
procedure TQueryThread.Execute;
begin
// 这里执行一个查询,在发出查询后,等待返回 (实际上就是休眠)
end;

// 启动线程
procedure ThreadStart;
begin
qt:=TQueryThread.Create(True);
QT_Handle:=qt.Handle;
with qtdo
FreeOnTerminate:=true;
// OnTerminate:=XXXXXX;
测试时可以用这个过程查看
Resume;
end;
end;

// 强行终止线程
procedure ThreadKill;
begin
TerminateThread(QT_Handle,ExitCode);
end;

可以代到实际的程序中进行测试,定义一下 OnTerminate 函数,
就可以看到线程被 Kill 了。关于数据库这样一个特定的环境,需要进一步测试,但
一般数据库都应该可以这样做的。
 
关注!
假如我在线程中用ADO建立和数据库的链接的话!
我怎么知道链接是否成功,有方法返回值没有?具体怎么做!
好象在线程中捕获异常是不好返回的吧????急啊急!!!!!!!!!!!!!
 
这位小雨兄弟好象自己还没怎么闹明白。
最好的方法就是通过线程异步实现线程对数据库的访问。
线程是一个对象,数据库访问器是另一个对象,两者间并不是面对面地交流。数据库访问器
可以归线程所有(线程释放的时候也顺便释放这个数据库访问器),也可以多个线程公用。无
论是什么方式,两者间保持异步效果最佳,也不会更多地占用系统资源。线程向数据库访问
器提交一个查询,然后进入自己的消息循环或事件循环或混合的循环中。不管是什么循环,
都会检测其Terminated的值,一旦为True,就有机会退出线程。将来数据库访问器执行完,
发回来的数据,丢弃就行了。如果数据库访问器支持消息打断或者任何一种什么方式打断的
话,退便线程的时候顺便打断一下就行了。
现在告诉你三种循环:
A.消息循环:
var
Msg: TMsg;
...
while not Terminateddo
while PeekMessage(msg, 0, 0, 0, PM_REMOVE)do
if .... then
//现在捕获到了需要的消息,处理这个消息
else
DispatchMessage(Msg);
这种方式不太好,消息循环太占用系统资源。
B.事件循环:
var
Event: THandle;
WaitTime: DWord;
...
while not Terminateddo
begin
WaitTime := 60000;
//1分钟够长吗?
case WaitForSingleObjects(1, Event, False, WaitTime, QS_ALLEVENTS) of
WAIT_OBJECT_0:
//现在捕获到了需要的事件,处理这个事件
WAIT_TIMEOUT:
//没有在预计的时间内收到需要的事件,处理超时
end;
end;
这种方式也不太好。等待时间内线程倒是休眠的,可是超时时长不好设。太短,没有多大意
义,太长,线程不好终止。因为循环等不到事件就得等超时。如果超时设为无限长,线程容
易死。
C.混合循环:
以上两种的结合。
var
Msg:TMsg;
Event:THandle;
WaitTime: DWord;
...
while not Terminateddo
begin
WaitTime := 60000;
//1分钟够长吗?
case MsgWaitForMultipleObjects(1, Event, False, WaitTime, QS_ALLEVENTS) of
WAIT_OBJECT_0:
//现在捕获到了需要的事件,处理这个事件
WAIT_OBJECT_0 + 1:
while PeekMessage(msg, 0, 0, 0, PM_REMOVE)do
if .... then
//现在捕获到了需要的消息,处理这个消息
else
DispatchMessage(Msg);
WAIT_TIMEOUT:
//没有在预计的时间内收到需要的事件,处理超时
end;
end;

这段代码好象在哪见过?是啊,是啊。就不告诉你。:)
 
你问的是数据库处理部分还是程序执行部分?
 
谢谢 barton 指教,这不是我的问题,我很清楚该怎么去做,甚至更多。
问题提出的本身不是如何建立一个线程,而是强制一个线程结束。强制一个线程结束,
可以如你的代码那样在线程创建时就考虑到多种情况,也可以直接使用系统函数 kill 。
这个没有问题。至于数据库,由于有多种类型,有支持中断的,有支持事务回滚的,有什
么也不支持的,总之和线程是两个不关联的对象,所以我觉得我这样做没什么不对,请进
一步指教。
说到消息沟通,你文中已经说得很透彻了,但既然罗列思路,应该将所有可能的考虑都写
出来,无非就是函数回调、消息回调、局部存储、消息循环、事件对象,出格一点考虑内
存共享也未尝不可,基于的无非是异步执行,假如是同步的呢?好不好暂且不论,是不是
还是要回到我的强制 kill 上来呢。请指教。
 
TThread线程结束的机制是自己结束,也就是调用TThread.Terminate方法,将Terminated
标志设为True,然后你什么也不用管了,由线程自己去处理。使用Kill杀线程倒是简单了,
可是如果线程结束的时候需要处理一些事务的话就没有机会了。之所以采用异步,目的正
是为了同步呀!你看看在线程的循环中每次都会检测Terminated的情况,退出了循环但还
没有退出线程,这时候可以做一些善后处理,然后很友善地结束线程。不是这样的吗?
 
我现在也遇到这类问题,还望barton, 小雨哥赐教!
我用DELPHI6.0和SQL SERVER2000基于MIDAS构建三层架构的数据库系统。现在遇到一个问题,
因为这个系统是要跟硬件接口的,这接口部分是读取硬件传来的txt,然后上传到数据库。现
在考虑到万一SQL坏掉的话,客户端与服务器起码要连半分钟才会报错,而客户要求能在3,4
秒内就能完成。也就是说,希望能做个线程先打开clientTable,(用的是socketconnection)
一旦SQL坏了或者是服务器程序没有运行起来,就在3,4秒后将这个线程kill掉。
我试着写了一段代码,用的是双线程,线程一就负责连接socketconnection和clientTable.open,
线程二就循环3秒钟,然后结束时去检测clientTable.active是否为true,如果是false(即表
没有打开),则kill线程二。
不过运行后,线程二到了时间还是kill不掉。不知何故,还望赐教!
 
In Oracle, there are a function called oci_break,
or you might create a new session to kill the Query seesion.
once the query is terminated, the thread will be quit,
terminate the thread is a bad idea
 
to hillliu:
搞不懂你的架构,感觉好乱。什么双线程,不懂。
1.使用事件:
先定义一个全局变量:
var
GlobalEvent: THandle;
在主线程启动时。建立这个共享的事件:
GlobalEvent := OpenEvent(EVENT_MODIFY_STATE + SYNCHRONIZE, False, 'Client_Table');
在主线程关闭时,释放这个事件:
CloseHandle(GlobalEvent);
将ClientTable的AfterOpen事件句柄中加入:
SetEvent(GlobalEvent);
在主线程中执行:
TMyThread.Create(False);
ClientTable.Open;
在TMyThread线程中:
var
WaitTime: DWord;
...
FreeOnTerminate := True;
while not Terminateddo
begin
WaitTime := 3000;
//超时设为3秒
case WaitForSingleObjects(1, GlobalEvent, False, WaitTime, QS_ALLEVENTS) of
WAIT_OBJECT_0:
begin
ResetEvent(GlobalEvent);
if ClientTable.Active then
//现在数据库表已经打开,爱干点啥就干点啥吧!
end;
WAIT_TIMEOUT:
begin
//在预期时间内未打开表,爱干点啥就干点啥吧!
Terminate;//自己终止自己
end;
end;
end;

2.使用消息
......
是这个意思吗?
 
to 小雨哥:
最好是用 TThread.Terminate 而不要用 TerminateThread 这个 API,他强制终止
一个线程虽然快,但是会导致相关的资源无法释放,而且不会触发 TThread.OnTerminate
事件。用 TThread.Terminate 虽然只是设置一个标志就返回了,可能比较慢,但是
安全。只要 TThread 内部没有死循环就没有问题。
 
后退
顶部