小白IT:Django框架—ORM中的锁和事务(难点)----建议作为熟悉~和了解

本文详细介绍了Django ORM中的行级锁,包括如何使用SELECT ... FOR UPDATE来实现,并讨论了其在不同数据库后端的支持情况。接着,探讨了Django的事务管理,包括全局开启事务的配置、局部事务的使用,以及事务的嵌套和注意事项,强调了避免全局事务以提高性能的重要性。
摘要由CSDN通过智能技术生成

一、orm中的锁

1.行级锁

mysql中,存储引擎是innodb时,是可以支持行级锁的,那么在orm中操作数据库时,为某一行数据开启行级锁只需要执行如下命令

select_for_update(nowait=False, skip_locked=False)

注意:

  • 行级锁必须用在事务里面
  • 所有匹配的行将被锁定,直到事务结束,这意味着可以通过锁防止数据被其它事务修改

返回一个锁住行直到事务结束的查询集,如果数据库支持,它将生成一个 SELECT … FOR UPDATE 语句。

举个例子:

entries = Entry.objects.select_for_update().filter(author=request.user)  #加读取互斥锁。create、update、delete操作时,mysql自动加行级互斥锁
  • 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参数。

使用不支持这些选项的数据库后端(如MySQL)将nowait=True或skip_locked=True转换为select_for_update()将导致抛出DatabaseError异常,这可以防止代码意外终止。

表锁(了解)

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(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值