第十一节:django中ORM的锁

django中ORM的锁

一、行锁

select_for_update(nowait=False, skip_locked=False)
注意必须用在事务里面,至于如何开启事务,我们看下面的事务一节 Book.objects.select_for_update().filter(nid=3)  # 锁住nid=3的行

# 数据库锁机制详见
https://www.cnblogs.com/linhaifeng/articles/14386584.html

select_for_update中的两个参数了解即可,因为在MySQL中压根不支持开启它们

一般情况下如果其他事务锁定了相关行,那么本查询将被阻塞,直到锁被释放。 如果这不想要使查询阻塞 的话,使用select_for_update(nowait=True)。 如果其它事务持有冲突的锁,互斥锁, 那么查询将引发 DatabaseError 异常。你也可以使用select_for_update(skip_locked=True)忽略锁定的行。 nowait和  skip_locked是互斥的,同时设置会导致ValueError。*
*
目前,postgresql,oracle和mysql数据库后端支持select_for_update()。 但是,MySQL不支持nowait和skip_locked参数。

二、表锁(了解)

class LockingManager(models.Manager):
    """ Add lock/unlock functionality to manager.

    Example::

        class Job(models.Model): #其实不用这么复杂,直接在orm创建表的时候,给这个表定义一个lock和unlock方法,
        # 借助django提供的connection模块来发送锁表的原生sql语句和解锁的原生sql语句就可以了,
        # 不用外层的这个LckingManager(model.Manager)类

            manager = LockingManager()

            counter = models.IntegerField(null=True, default=0)

            @staticmethod
            def do_atomic_update(job_id)
                ''' Updates job integer, keeping it below 5 '''
                try:
                    # Ensure only one HTTP request can do this update at once.
                    Job.objects.lock()

                    job = Job.object.get(id=job_id)
                    # If we don't lock the tables two simultanous
                    # requests might both increase the counter
                    # going over 5
                    if job.counter < 5:
                        job.counter += 1                                        
                        job.save()

                finally:
                    Job.objects.unlock()

    """    

    def lock(self):
        """ Lock table. 

        Locks the object model table so that atomic update is possible.
        Simulatenous database access request pend until the lock is unlock()'ed.

        Note: If you need to lock multiple tables, you need to do lock them
        all in one SQL clause and this function is not enough. To avoid
        dead lock, all tables must be locked in the same order.

        See http://dev.mysql.com/doc/refman/5.0/en/lock-tables.html
        """
        cursor = connection.cursor()
        table = self.model._meta.db_table
        logger.debug("Locking table %s" % table)
        cursor.execute("LOCK TABLES %s WRITE" % table)
        row = cursor.fetchone()
        return row

    def unlock(self):
        """ Unlock the table. """
        cursor = connection.cursor()
        table = self.model._meta.db_table
        cursor.execute("UNLOCK TABLES")
        row = cursor.fetchone()
        return row 
上一篇
下一篇
Copyright © 2022 Egon的技术星球 egonlin.com 版权所有 帮助IT小伙伴学到真正的技术