各位兄弟姐妹们,小弟有一问题很是头疼。
一CS结构软件,在每个登录者登录后都有一个已登录标记,用来判断不能用同一用户名同时在不同机器上登录,但现在的问题是一旦发生非法退出或是死机等情况后,已登录标记并没有改过来,出现下次不能登录的情况,需要到服务器的数据库里改一下。怎么能判断出非法退出或是死机等情况,把相应的代码写进去呢?

解决方案 »

  1.   

    在出现异常的时候改数据库!不过什么时候出现异常,就不大好说了
    在可能出现异常的地方
    tryexceptend
    楼主好运
      

  2.   

    我是初级,功力不够,还望高手指点在什么地方可能出现异常,
    tryexceptend
    语用在什么地方写啊
      

  3.   

    你最好在登录后在表中记录该操作员登录使用的计算机名称这样在用户每次登录的时候检查是否表中存在的纪录中涉及到的hostname不在系统表中则删除
    从系统表中查询即可
    delete mytable where hostname not in(select hostname from master.dbo.sysprocesses)if exists(select * from mytable where operator=@operator) 
     --表示用户正在登录使用中
      

  4.   

    每隔一段时间发送一个字符串,比如“CONN”,客户端接到字符串是判断,如果是“CONN”的话,表面不做变化,但后台发送“TRUE+机器名”到服务端
    如果服务端接到了回应字符,将发回的机器名重新整理就得到新的在线目录
    如果是在原目录基础上更新的华(不是CLEAR后重组),如果匹配不上的就显示“机器名+掉线”
      

  5.   

    异常处理在有占内存的地方
    例如
     query:TADOquery;----try
      query:=TADOQUERY.CREATE(NIL);
    exceptend
      

  6.   

    能告诉我具体的语句写在哪里吗,是写在
    tryexcept
    之间吗?
      

  7.   

    zswangII 老兄的說法, 應該是比較標準的做法, 建議考慮!我還有個想想法:
     每次client登錄, 驗證後, server 生成一個授權ID分配給 client, 保存在client 中,
     然後, Client 每當有關鍵查詢 or 提交時, 必須帶有驗證ID一并提交
      

  8.   

    关键问题就是要求服务器能够区分是用户掉线了,还是一个拖沓的用户正在进行操作。
    类似于浏览网页时的操作超时,可以用 zswangII(伴水清清)的方法解决。
      

  9.   

    伴水的办法是比较可靠,不过,开销太大可以利用数据库事务来实现,设你的登陆用户表为
    T_LOGINED_USER ( USER_NAME, HOST_NAME )另外设立一个同步表
    T_SYNC ( DUMMY )
    INSERT INTO T_SYNC VALUES ( 0 );对于每个登录客户,是用3个事务来防止同一用户在不同机器上登陆T1 (在READ COMMITTED级别下)
    T2 (READ UNCOMMITTED)
    T3 (READ COMMITTED)每一个登陆都依照下面的过程:
      T1 START
      T1 WRITE (UPDATE T_SYNC SET DUMMY = 0)
      T2 START
      T2 READ (EXISTS(SELECT * FROM T_LOGINED_USER 
               WHERE USER_NAME = :USER_NAME AND HOST_NAME = :HOST_NAME))
         IF EXISTS  T1 COMMIT, T2 COMMIT, ABORT
         ELSE CONTINUE
      T3 START
      T3 INSERT INTO T_LOGINED_USER VALUES (:USER_NAME, :HOST_NAME)
      T2 COMMIT
      T1 COMMIT  SUCCESS(注,不要提交T3)退出登录时,T3 ROLLBACK假锁的情况:当客户端突然丢失连接时,服务器不是马上就知道客户端已经退出,
    这里有一段假锁的时间,这段时间里,
    因为在T2 READ这一步发现一个记录,用户不能重新登录,
    当服务器被通知TCP/IP连接已经异常断开,服务器会回滚T3,
    这时用户才可以恢复登录不过这个假锁时间是可以通过WINDOWS设置调整成比较短的,
    也有些数据库提供检查事务活动性的功能,这也可以利用,
    或者通过管理员,强制尚在活动的T3事务回滚,这样用户就马上可以恢复登录了
      

  10.   

    回去想了想,发现自己说的T1和T2,以及T_SYNC表都是多余的,
    顾不上睡午觉,修正一下,其实只用T3一个事务就可以了,
    在登录时,INSERT INTO T_LOGINED_USER VALUES (:USER_NAME, :HOST_NAME)
    如果有重复记录,肯定触发异常,退出时,rollback T3就行了
      

  11.   

    to alphaxT3 START
    T3 INSERT INTO T_LOGINED_USER VALUES (:USER_NAME, :HOST_NAME)
    SUCCESS(注,不要提交T3)不知道以上语句要在哪里写,是代码里,还是在触发器里写呢?能具体说说详细的步骤吗,我不太明白,谢谢了!
      

  12.   

    在代码里写首先数据库里应该定义一个表,CREATE TABLE T_LOGINED_USER (
       USER_NAME VARCHAR(32) NOT NULL,
       HOST_NAME VARCHAR(64) NOT NULL,
       PRIMARY KEY (USER_NAME, HOST_NAME)
    );该表不要有任何内容,
    登录的时候,单独启动一个事务,然后执行SQL语句
    INSERT INTO T_LOGINED_USER VALUES ('用户名', '登录所在机器名')
    如果遇到关键字重复的错误,那么说明用户重复登录了
    如果没有问题,用户就可以顺利登录这就OK了,
    注意是要一直保持这个事务,不要提交它,直到用户注销登录时,
    就回滚这个事务
      

  13.   

    to alphax我是这样写的代码,帮我看看哪里有问题procedure TForm1.Button1Click(Sender: TObject);
    begin
       ADOConnection1.BeginTrans ;
       try
          ADOCommand1.CommandText :='INSERT INTO USER1 VALUES (11,111)';
          ADOCommand1.Execute ;
       except
       '提示出错代码
    end;
    end;procedure TForm1.Button2Click(Sender: TObject);
    begin
       ADOConnection1.RollbackTrans;
       close;
    end;运行后,1.如出错的话Except语句不执行。2.我用同一机器同一用户登录后非法退出,然后在进也是可以的啊,现在只是程序没退出时不能同时登录,程序退出后就不起什么作用了。
      

  14.   

    >>2.我用同一机器同一用户登录后非法退出,
    >>然后在进也是可以的啊,
    >>现在只是程序没退出时不能同时登录,
    >>程序退出后就不起什么作用了>>现在的问题是在两台机器上分别登录可同时登上去。
    >>在一台机器上登录两次不可以。你要得不就是这种情况吗?
    如果要求在服务器中,不管在那一台机器,一个用户只能登录一次的话,
    把HOST_NAME字段去掉就可以了如果你要求用户非法退出以后不能重新进入的话,就必须使用其他办法了,
    我的办法是确保非法退出以后仍能进入
      

  15.   

    to alphax我照你说的改了,是写入用户名,但还是无法阻止一个用户名同时在两台机器上登录的情况
    代码如下:
    procedure TForm1.Button1Click(Sender: TObject);
    begin
       ADOConnection1.BeginTrans ;
       try
          ADOCommand1.CommandText :='INSERT INTO USER1 VALUES (11)'; ’这里只写入用户 名为11
          ADOCommand1.Execute ;
       except
       '提示出错代码(不知道为什么,出错时不执行这里的代码)
    end;
    end;procedure TForm1.Button2Click(Sender: TObject);
    begin
       ADOConnection1.RollbackTrans;
       close;
    end;在次谢谢了
      

  16.   

    你的是什么数据库,SQL Server吗?
    我没有SQL Server,测试不了为什么不行,因为你在本地不能同时插入同一记录,
    那么对于其他机器来说,数据库也是一样处理的
    不明白为什么不行
      

  17.   

    我这是SQL Server的数据库,在本地提示你不能插入同一条记录,但在两台机器上时,一台登录后另一台在登录时出现‘程序未响应’情况。不知道为什么。
    在有
    tryexceptend
    语句在出错时为什么Except语句下的代码不执行呢?
      

  18.   

    不对,你试一下在另一台机器用别的用户名登录,看看是否也在等待,
    如果是的话,我的这种办法就不OK了没有深入了解过sql server,不知道它具体的锁定策略是怎样的
      

  19.   

    to alphax:
    我试过了,用别一台机器用别的用户名登录没问题。用同一用户名登录出现程序未响应情况,但关掉前一台机器的程序后,后一台机器的程序就又响应了。不知道怎么解决这个问题啊,苦啊!急盼另请看看是不是代码哪里写的不对啊!!!var
      Form1: TForm1;
      pan :string;
    implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);begin
    tryADOCommand1.CommandText :='INSERT INTO USER1 VALUES (''' + pan + ''')';
    ADOCommand1.Execute ;
    except
      application.MessageBox('ok',pchar('ok'));
    end;
    end;procedure TForm1.Button2Click(Sender: TObject);
    begin
    ADOConnection1.RollbackTrans ;
    close;
    end;procedure TForm1.FormCreate(Sender: TObject);begin
    pan:='pan';
    ADOConnection1.BeginTrans ;
    end;
      

  20.   

    昨晚想了一下,我这个办法是不通用的,因为这依赖于数据库后台的锁定策略,
    如果事务在执行插入时持有的是数据页锁或者索引页锁而不是行级锁那就不OK了,
    这是要说明的,比较可靠的是用伴水的办法,
    要不嫌开销大就自己做一个控制服务程序,,,从你的情况上看来,估计是因为插入相同的记录导致了等待,
    而不是因为页的锁定而发生等待,
    那么你可以设定超时,SQL Server好像有个set 什么timeout的SQL命令,
    你查看一下ADO或者TSQL的文档,应该有的
      

  21.   

    to  panyu1979 (panyu1979)  :
    我以前的程序中也和你有同样的想法,但是后来的实践中发现太失败了,因为系统的异常情况
    太复杂,sql server中的事务锁也不能十分准确。导致用户非正常关机后程序经常不能用了。
    能的客户怨声载道,我劝你还是把精力用在让程序更加健壮上面去,一个用户的密码是关键,如果他把密码泄漏了,问题在他们,如果他是自己重复登陆,那有什么办法,他要想自己破坏你的系统了,水都没办法。你要把微软的<windows>目录下的东西给删除了,系统不也瘫痪了吗?软件的使用也要规范的。我们程序员无法阻止所有的非法操作。