if notication.has_readed:
return
notification.has_readed = True
notification.save()
# 在这里更新我们的计数器,嗯,我感觉好极了
self.update_unread_count(-1)
除了使用``select for update``这样的功能,还有一个比较简单的办法来解决这个问题。
使用update来实现原子性修改
其实,更简单的办法,只要把我们的数据库改成单条的update就可以解决并发情况下的问题了:
def mark_as_readed(self, notification_id):
affected_rows = Notification.objects.filter(pk=notification_id, has_readed=False)
.update(has_readed=True)
# affected_rows将会返回update语句修改的条目数
self.update_unread_count(affected_rows)
这样,并发的标记已读操作也可以正确的影响到我们的计数器了。
高性能?
我们在之前介绍了如何实现一个能够正确更新的未读消息计数器,我们可能会直接使用UPDATE 语句来修改我们的计数器,就像这样:
from django.db.models import F
def update_unread_count(self, count)
# 使用Update语句来更新我们的计数器
UserNotificationsCount.objects.filter(pk=self.user_id)
.update(unread_count=F('unread_count') + count)
但是在生产环境中,这样的处理方式很有可能造成严重的性能问题,因为如果我们的计数器在频繁 更新的话,海量的Update会给数据库造成不小的压力。所以为了实现一个高性能的计数器,我们 需要把改动暂存起来,然后批量写入到数据库。
使用 redis 的 sorted set ,我们可以非常轻松的做到这一点。
使用sorted set来缓存计数器改动
redis是一个非常好用的内存数据库,其中的sorted set是它提供的一种数据类型:有序集合, 使用它,我们可以非常简单的缓存所有的计数器改动,然后批量回写到数据库。










