The puzzle about the use of setex locks in 6-9 code snippets in "redis practice"

After thinking about it for a long time, I really can"t understand how locks are used in listing 6-9. Locks are only set with a key, and are not used at all (such as if getkey () = = true and so on). The generated locks are still random, that is, the concurrency problem is not solved. It is still possible for other clients to operate on the data at the same time.
ask the boss to solve the problem, thank you.

-sharp  6-8
-sharp <start id="_1314_14473_8641"/>
def acquire_lock(conn, lockname, acquire_timeout=10):
    -sharp 128
    identifier = str(uuid.uuid4())                     

    end = time.time() + acquire_timeout
    while time.time() < end:
        -sharp 
        if conn.setnx("lock:" + lockname, identifier): 
            return identifier

        time.sleep(.001)

    return False
-sharp <end id="_1314_14473_8641"/>


-sharp  6-9
-sharp <start id="_1314_14473_8645"/>
def purchase_item_with_lock(conn, buyerid, itemid, sellerid):
    buyer = "users:%s" % buyerid
    seller = "users:%s" % sellerid
    item = "%s.%s" % (itemid, sellerid)
    inventory = "inventory:%s" % buyerid

    -sharp 
    locked = acquire_lock(conn, "market:")   
    if not locked:
        return False

    pipe = conn.pipeline(True)
    try:
        -sharp 
        pipe.zscore("market:", item)        
        pipe.hget(buyer, "funds")            
        price, funds = pipe.execute()         
        if price is None or price > funds:   
            return None                     

        -sharp 
        pipe.hincrby(seller, "funds", int(price)) 
        pipe.hincrby(buyer, "funds", int(-price)) 
        pipe.sadd(inventory, itemid)            
        pipe.zrem("market:", item)               
        pipe.execute()                           
        return True
    finally:
        -sharp 
        release_lock(conn, "market:", locked)   
-sharp <end id="_1314_14473_8645"/>


-sharp  6-10
-sharp <start id="_1314_14473_8650"/>
def release_lock(conn, lockname, identifier):
    pipe = conn.pipeline(True)
    lockname = "lock:" + lockname

    while True:
        try:
            -sharp 
            pipe.watch(lockname)                  
            if pipe.get(lockname) == identifier:  
                -sharp 
                pipe.multi()                  
                pipe.delete(lockname)      
                pipe.execute()             
                return True                    

            pipe.unwatch()
            break

        -sharp ;
        except redis.exceptions.WatchError:     
            pass                                 

    -sharp 
    return False                                
-sharp <end id="_1314_14473_8650"/>
Mar.17,2021

Please take a closer look at the manual. The setnx command is that if the key is not set in the current redis, it will return 1 if it is successfully set, otherwise if it fails to set, it will return 0, and it will be used as a lock. This feature is taken advantage of, and it does not matter what value is set.


from an example, only one operation using setnx, in acquire_lock can lock successfully. And redis is single-process, and all commands are processed one by one serially. So I don't think there is any concurrency problem

Menu