提问:SQL中的INSERT INTO ... SELECT ...
  
  现有个表,记录用户账户存款的 users_id | created | amount | post_balance
  
  created是该次交易的时间,
  amount指该次交易的数额,
  post_balance是该次交易后的用户账户余额。
  
  post_balance是根据之前最后一次的post_balance + 当前这次的amount得到的。
  
  那么我想用
  INSERT INTO xxx (users_id, amount, post_balance) 
  VALUES (10002, 100.00, amount + (SELECT post_balance FROM xxx ORDER BY created DESC limit 1))
  
  因为这条语句用SELECT来选择之前最后一次的post_balance记录,
  这样,如果发生并发,就是有2条以上的上述INSERT语句,对同一个用户操作会不会发并发造成的错误?
  即:两个SELECT语句查询出来的post_balance结果相同,分别计算再分别INSERT,就会导致其中一条的amount丢失,没有加到post_balance中区呢?如果会有这样的错误,那么应该怎么修改呢?
  
  谢谢各位大侠了!

解决方案 »

  1.   


    呃,可以具体一点么,我是在程序里写SQL语句,怎么使用事务,怎么加锁呢?
    最好写出来SQL语句吧~我是SQL新手,十分感谢!
      

  2.   

    MySQL官方文档 http://dev.mysql.com/doc/refman/5.1/zh/index.html
      

  3.   

    INSERT INTO xxx (users_id, amount, post_balance)  
      VALUES (10002, 100.00, amount + (SELECT post_balance FROM xxx ORDER BY created DESC limit 1))你这个语句有逻辑错误吧。
    SELECT post_balance FROM xxx ORDER BY created DESC limit 1
    得到的是这个表的最新的一条记录,但是没有指定是哪个USERID,这样得到的结果是错误的。INSERT INTO xxx (users_id, amount, post_balance)  
      VALUES (10002, 100.00, amount + (SELECT post_balance FROM xxx where users_id=10002 ORDER BY created DESC limit 1))
      

  4.   

    第二个问题可以用事务来解决。START TRANSACTION;
    SELECT @A=post_balance FROM xxx where users_id=10002 ORDER BY created DESC limit 1;
    INSERT INTO xxx (users_id, amount, post_balance)VALUES (10002, 100.00,@A);
    COMMIT;数据库里是这样进行事务操作的。不同的开发工具有它对应的事务处理方法。
      

  5.   


    您说的太对了!其实程序里的SQL是有写users_id的,写到论坛里的时候,给忘了……
      

  6.   


    非常感谢~
    不过我忘了说,我用的是postgresql ^_^,受你的启发,我去查了一下psql的文档,发现LOCK TABLE必须用在事务中,在commit之前该表被锁定。但是我们的项目约定不能用事务……我悲剧了大侠们还有别的招么?