做項目的時候,往往都是多用戶的版本,在多個人同時操作一個表時,程序如果處理不好,就會發生混亂,找了很多資料,也看了很多貼,但是都沒有一個有效的方法;很多都講到使用鎖功能,但這個功能我確實沒有用過,所以在此發帖,希望有這方面經驗的朋友指點,先謝過了!

解决方案 »

  1.   

    碰到並發執行,一般需要解決幾個問題:1.数据修改互相覆盖的问题
      同样一笔订单,业务员A可能在修改,而主管B可能正要审核。这时,就需要处理,不能说B主管审核成功之后,业务员A又修改成功了。
      解决方法:记录增加版本(时间戳记或整形等),更新时根据版本号更新。被别人更新后,当前更新就不成功(更新笔数为0,生成的SQL可能是如:update order set version = version+1, comment='请及时出货' where orderId=123334 and version=3)2.多人同时操作,尤其有人进行批量更新时锁定表而造成的效率问题
      对于经常使用的DB来说,可能锁的管理是由DB自动管理的。此时,如果有人进行批量更新(如:整批将财务凭证过账),此时可能有人也需要查询这个表,就可能会造成因为表被锁而等待。这就需要对应用进行优化(这种业务一定会出现):
      A.批量更新尽量在用户少的时候做,比如:将批量调整作业排程,放到晚上去做
      B.批量操作的事务尽可能的小...不要修改1W笔才提交,可以500笔一提交,减少占用资源的时间
      C.某些查询可以使用with no lock的脏读方式提高查询的效率3.主数据修改与应用的问题
      系统的一些主数据,如:品号/仓库/客户/供应商/BOM/等,是关系整个系统的数据,这些数据在修改时,往往要求其它人员不能使用(没有在使用这些数据录单), 此时应该有相应的提示. 可以通过将修改中的主数据做标记(或通过数据库技术:据说QAD?是使用的这种,我不会),选择或保存时做检查.
      

  2.   

    其实这个问题是很常见的,多数都是加锁来防止丢失更新情况的发现.
    加锁有两种方法,一种是悲观锁,一种是乐观锁
    所谓悲观锁就是当访问一个表时就认为可能会有人在更改表,所以先加锁,让其它用户都访问不了.
    乐观锁,则是认为不会有人更改,只有当前用户修改后提交的时刻才开始进行验证,如果发现有人修改过了,就回滚事务,这样做的坏处就是可能做了一堆的工作,最终时刻回滚导致要重做,但这是最常用的.
    加锁的办法:select * from table for update这样进行锁表完成修改等后,commit释放锁.
    还可以在一个表中加一个更新字段(一般是日期的精确到毫秒),在查询浏览或修改前先记住这个值,待修改提交时验证当前的字段值与开始记住的值是否相同,如果相同则没有人修改,如果不同则证明有人修改过了,需要重新刷新进行新的修改操作,对于这个字段的维护,可以加一个触发器实时的去更新这个字段,这与楼上说的版本号更新基本是一个意思.
      

  3.   

    更新时根据版本号更新’是怎么回事::在数据表中增加一个字段为版本号, 如version int default 0
    每次更新时需要将version加1, 这个可以通过触发器实现或自己在update语句中写. 当然, 如果使用时间戳就由DB帮忙维护(MS SQL SERVER). 
    而在对这个表更新时, 一定要把这个version作为更新条件加入到到update的where语句中. 
    而这个来源就是你读取时得到的version, 这样, 如果两个人同时读到同一笔记录进行修改. 如A读到version 为 1 , B也读取version为1, 
    然后A先保存, 此时数据库中此记录的版本就变成2, update table1 set version = 2 where id='33333' and version = 1
    然后B在提交时,也会生成语句:update talbe1 set version=2 ... where id='33333' and version=1
    由于version已经被A修改为2, 造成B的更新失败(version已经不是1了), 所以就提示B, 你的数据已经被别人修改过了. 并读取最新的数据给B修改. 
      

  4.   


    谢谢,我明白了;把版本作为一个更新必要的条件来维护,这个方法真的很好;另 ----〉如果使用时间戳就由DB帮忙维护(MS SQL SERVER)---对我来说是个新的概念
    你提到时间戳,时间戳我以前没有用过,刚刚查看了一些资料,明白它的意思了,但我还想问的是:
    1.时间戳是由sql自己维护,是否我们在程序中可以不用理会它,就像自增字段一样;
    2.如何获取时间戳,是否可以用Adoquery.filedbyname('deta').asdatetime来读取;
    3.如果设置变量,把时间戳类型的数据赋值给变量的话,那么变量是否该申明成datetime类型,还是其他类型;以上,盼望回复!
      

  5.   

    通常,读取时,不需要锁记录。更新时,需要锁。
    当某一条记录被编辑时(处于编辑状态中),为了不发生脏数据的读取(老数据被读取、处理),应该进行记录锁定。
    这个可以在数据库概论书中进行了解。下面是实际应用中的情况:
    数据库级:
    数据库不一样,锁定方式也不一样。有的根本不锁(个人数据库),有的表锁定(小数据库),有的记录锁定(大中型数据库)。当然,大型数据库通常都可以根据你在命令行中的显式要求判断是否锁定、及进行什么级别的锁定。
    如果通过ODBC或其他什么桥连接的方式,根据驱动读取被锁定的表或记录的情况也不太一样。
    比如:某中小型数据库在记录被编辑时,通过数据库自身客户端读取是记录锁定,但通过ODBC连接读取时是整张表都被锁定了(可能简化了ODBC的开发)。
    用户级:
    就是很多人说的自己开发一个锁机制。说白了就是通过冗余的字段进行判定。可以是状态,时间,操作人等等。只要能满足需求就好。