Home  >  Q&A  >  body text

node.js - nodejs单进程产生的数据库连接多线程并发问题探讨

举例,假设有100个请求node服务器,每个请求会执行一次查询,修改数据库操作。假设10个请求按顺序被node接收处理 等待各自判定库存查询数据库io操作,但是库存只有5个,问题来了,这时候10个查询都判定库存还有,然后继续下面的下单操作。当100个请求甚至更多时,问题会被更加放大 又不能同步加锁,哪位朋友有比较合理的思路 不吝赐教~

怪我咯怪我咯2742 days ago916

reply all(4)I'll reply

  • 高洛峰

    高洛峰2017-04-17 15:52:35

    Search "snap up" on the site
    https://segmentfault.com/sear...

    Extreme cases are "flash sales"
    https://segmentfault.com/sear...

    reply
    0
  • 大家讲道理

    大家讲道理2017-04-17 15:52:35

    In this case, you should add affairs

    ----- Update the answer -----

    The problem of inconsistency between query and actual data is unavoidable. My understanding of the question is that if other users successfully purchase before updating the callback, it will cause the purchase failure problem. Therefore, it can be solved by locking. In fact, if it is asynchronous When all operations use promises, you can simulate sequential calls through Promise to achieve features similar to Java method locking

    Use decorator to implement synchronous calls similar to the java synchronized keyword on methods that return promises

    
    // decorator
    
    let p
    function sync(target, name) {
      const method = target[name]
      target[name] = function(...args) {
        if (p) {
          p = p.then(() => method.apply(target, args))
        } else {
          p = method.apply(target, args)
        }
        return p
      }
    }
    
    class Model {
      constructor () {
        // super()
        this._cardCount = 5
        sync(this, 'buyOneCard')
      }
      // @sync // 注解需要编译,暂时手动调用下
      buyOneCard (user) {
        console.log('buyonecard', this._cardCount)
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            this._cardCount = --this._cardCount
        
            this._cardCount < 0
              ? reject(this._cardCount)  
              : resolve(this._cardCount)
          }, 100)
        })
      }
    }
    
    const m = new Model()
    for(let i=0;i<10;i++) m.buyOneCard().then(c => console.log(c))

    Passed when running under chrome. .

    ----- Update again ----

    There are already similar tools on github
    https://github.com/sindresorh...

    reply
    0
  • 巴扎黑

    巴扎黑2017-04-17 15:52:35

    Thank you to the two people above. First of all, the scenario I described is normal product sales. If it is a rush purchase, it is easier to handle. It can be solved directly by using redis queue, but this method is not advisable when there are many types of products.

      回复楼上,这里面事务是肯定有的,但是事务并不能解决这种并发超卖的情景。
    
     最后,如果这是用java可以很方便用队列或同步锁解决,但是node并不适用以上场景,redis也只能解决抢购,谁有还有合适的方案 ,期待中~
    

    reply
    0
  • 阿神

    阿神2017-04-17 15:52:35

    Transaction + condition update avoids oversold by design.

    reply
    0
  • Cancelreply