V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
huage
V2EX  ›  问与答

SQL Server 会同时执行两条 SQL 语句吗?我指的是同一时间点上执行,而不是先后。

  •  
  •   huage · 2014-11-13 18:03:04 +08:00 · 8201 次点击
    这是一个创建于 3662 天前的主题,其中的信息可能已经有所发展或是发生改变。
    比如说在进销存管理系统里,业务上经常会同时发生以下两种情况:

    仓管在录入入库单:原库存 + 入库 = 新库存

    但在同时

    销售部也在开销售单:原库存 - 出库 = 新库存

    上面两个业务可以简单理解为两条SQL语句,请问两条语句会在同一时间点上执行吗? 就是说会不会两条语句都以“原库存”为基数进行加或者减呢?

    sql server本身是否有机制防止这种情况的发生呢?
    18 条回复    2014-11-14 08:56:37 +08:00
    takwai
        1
    takwai  
       2014-11-13 18:17:13 +08:00   ❤️ 1
    sql server 有并发控制类型 http://technet.microsoft.com/zh-cn/library/ms189132(v=sql.105).aspx

    需要在 Transact-SQL 语句或通过数据库应用程序编程接口的属性和特性来定义。
    msg7086
        2
    msg7086  
       2014-11-13 18:19:51 +08:00 via iPhone   ❤️ 1
    事务。
    huage
        3
    huage  
    OP
       2014-11-13 18:25:21 +08:00
    @takwai 可以这样理解吗?如果不定义,SQL server本身是有可能发生这种情况的。一旦这个风险真的出现了,新的库存数量就不正确了。
    huage
        4
    huage  
    OP
       2014-11-13 18:26:02 +08:00
    @msg7086 能否详细指点一下?谢谢!
    incompatible
        5
    incompatible  
       2014-11-13 18:32:09 +08:00   ❤️ 1
    @huage 你需要了解的是事务隔离级别这个概念
    http://en.wikipedia.org/wiki/Isolation_%28database_systems%29
    http://msdn.microsoft.com/zh-cn/library/ms173763.aspx


    具体到你的情况 入库和销售这两个业务在共同操作库存这个资源,这样需要一个锁来保证两个业务各自的原子性
    通常的做法是在业务系统中使用乐观锁或悲观锁来解决这个问题,而不是依赖数据库的事务隔离
    zts1993
        6
    zts1993  
       2014-11-13 18:36:14 +08:00 via Android   ❤️ 1
    锁和事物

    如果是sql执行加减,数据库自动行锁或者表锁可以保证正确。一般是没有问题的,烦心的话就加锁。


    上面说事务是不对的吧,事务保证多步操作正确,这里是单条记录。
    huage
        7
    huage  
    OP
       2014-11-13 19:09:07 +08:00
    @zts1993 我刚才问了一位SQL MVP,他很耐心地回答了我的问题,大概如下:

    在单核计算机上不会同时执行,都会排队,在多核计算机上,会有可能同时执行。四核处理器,会有四个队列,每个队列都有sql语句排队,如果两条sql语句不在同一个队列,那么可以认为是同时执行,当然,如果由于排队机制,两个sql语句在两个核心上同时执行的可能性太少了,但是宏观上可以认为是同时执行。

    为了保证执行的先后顺序,你必须加锁WITH(UPDLOCK)

    如果不加锁的话,可以考虑sql2008的新的merge关键字
    不过实际上在内部都是加了锁的
    要保证执行顺序的一致性,也就是保证所谓的串行,反正会造成更新丢失,库存不一致


    他提到的一个问题是:更新丢失。
    liprais
        8
    liprais  
       2014-11-13 19:27:45 +08:00   ❤️ 1
    楼主你先要了解下SQL server的隔离机制,
    随手一搜,这里就有:http://technet.microsoft.com/zh-cn/library/ms189122(v=sql.105).aspx
    永远记住先搜索再提问
    huage
        9
    huage  
    OP
       2014-11-13 20:22:41 +08:00
    @liprais 是的,我是应该先搜索,这种菜鸟问题确实麻烦了V2EX了各位大神了。

    不过由于我对于SQL没有很多基础上,许多名词不知道,所以搜索出来的结果不是很满意,特来到这里向大家请教。
    20150517
        10
    20150517  
       2014-11-13 20:32:27 +08:00 via Android
    @zts1993 是啊,update行,肯定是锁行的,不需要事务这么麻烦,事务锁表了吧?
    liprais
        11
    liprais  
       2014-11-13 21:12:59 +08:00 via iPad   ❤️ 1
    @huage 推荐ni翻一遍head first sql这本书
    mengskysama
        12
    mengskysama  
       2014-11-13 23:19:16 +08:00
    @20150517
    也不一定,只有 InnoDB有行锁,其他都是锁表的比如SAM。

    每一个数据库语句肯定是先取得锁再操作的,锁是线程之间共享的不管你几个核心,但是有些锁是共享的,多线程的时候必须要考虑到逻辑正确性(多个线程同时操作,某些线程更新了某条记录)可能就会出现数据不一致。

    这个例子似乎两sql之间不能保证原子和互斥。这个问题我只知道可以用事务解决,既然能够保证多线程的正确性,又能保证顺序的完整性要么操作都成功要么失败。
    mengskysama
        13
    mengskysama  
       2014-11-13 23:21:04 +08:00
    @huage 哦哦是微软数据库啊,不过应该都一样,差不多就是MVP说的那个意思。
    min
        14
    min  
       2014-11-13 23:43:47 +08:00 via iPhone
    买本书看看吧
    msg7086
        15
    msg7086  
       2014-11-14 03:46:58 +08:00   ❤️ 1
    有冲突的记录,数据库上会自动加锁保证操作的原子性。

    如果是先读再写,为了防止两条记录前后分别执行,则需要加事务。
    huage
        16
    huage  
    OP
       2014-11-14 08:37:29 +08:00
    @liprais head first系列的图书确实不错,适合我这些初学者,简单易懂很有趣味。
    huage
        17
    huage  
    OP
       2014-11-14 08:38:43 +08:00
    @msg7086 像我所提及有这种业务情况,应该就是先select,后insert的吧。
    msg7086
        18
    msg7086  
       2014-11-14 08:56:37 +08:00 via iPhone
    @huage 不一定的。你这种计算可以直接在服务器上执行,不需要2句的。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1699 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 16:42 · PVG 00:42 · LAX 08:42 · JFK 11:42
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.