今天的好奇心解决主题是 Django的request.session.get()会导致性能下降吗? 🎯
在进行Django开发时,通常会多次调用 request.session.get('key_name')
。但是,突然有这样的想法。
"如果会话最终存储在数据库中,那么每次调用
request.session.get()
时都发生数据库查询吗?""或者,Django是否进行了聪明的处理,以避免额外的查询?"
为了解决这个疑问,我深入研究了Django的 SessionMiddleware源码,并通过实验进行了验证。 🚀
1️⃣ Django如何创建request.session?
我们来看看Django在创建request对象时何时加载会话。
我们通常在 视图函数 中这样获取会话数据。
session_username = request.session.get('username')
但是,如果每次使用 request.session.get('username')
时Django都要 发送数据库查询,那么将对性能造成很大影响吧?
🔍 让我们看看Django的内部!
实际上,Django通过 SessionMiddleware
中间件,在请求到达时 预先加载会话数据。这个过程只发生一次数据库查询,之后 会话数据保持在request对象中。
查看Django的 SessionMiddleware
代码,可以看到以下处理。
class SessionMiddleware(MiddlewareMixin):
def process_request(self, request):
session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
request.session = self.SessionStore(session_key)
📌 这里的重要点!
- ✅ 从
request.COOKIES
中获取会话密钥(session_key
)。 - ✅ 调用
self.SessionStore(session_key)
,会话数据 仅从数据库中获取一次并保存在request.session中。 - ✅ 也就是说,即使在视图函数中多次调用
request.session.get()
,也不会发生额外的数据库查询! 🎯
2️⃣ request.session.get()会产生数据库查询吗?
现在回到核心问题。
"在视图中调用
request.session.get('username')
会导致数据库查询吗?"
🚀 简单地说,调用 request.session.get()
并不会产生额外的数据库查询。
原因很简单。
✔ Django在 请求到达时加载会话数据一次,然后存储到 request.session
中。
✔ 而后调用 request.session.get()
只是 获取已加载到内存中的数据,因此不需要额外的数据库查询。
实际上,从数据库中查询会话的时刻是在请求开始时仅一次。 这时执行的SQL查询如下:
SELECT session_data FROM django_session WHERE session_key = 'xyz123' LIMIT 1;
换句话说,✅ 在视图中多次调用 request.session.get()
时,Django不会执行额外的数据库查询!
✅ 从数据库中获取数据仅在请求第一次发生时执行一次!
3️⃣ 在模板中使用会话数据时也会产生查询吗?
"在视图中查询会话数据后传递给模板,模板中使用时也会产生额外的数据库查询吗?"
例如,假设在视图中这样传递会话数据。
def my_view(request):
session_username = request.session.get('username') # 发生数据库查询吗? ❌
return render(request, 'my_template.html', {'session_username': session_username})
然后在模板中使用如下。
<p>登录为: {{ session_username }}</p>
在这种情况下也不会产生额外的数据库查询!
✔ session_username
是 已经从request.session获取的值,因此Django在传递给模板时不需要额外的数据库查询。
✔ Django像 request.session
进行 内存缓存管理,因此在模板中也可以安全使用。
4️⃣ 修改会话数据时会存储到数据库吗?
"那如果像这样修改数据
request.session['username'] = 'new_value'
呢?"
🚀 在这种情况下,与数据库的更改被存储,并且会产生额外的数据库查询!
如果像下面这样修改会话数据,
request.session['username'] = 'new_value'
Django会在发送响应时将 修改后的会话数据存储到数据库。这时执行的SQL查询如下:
UPDATE django_session SET session_data = 'new_value' WHERE session_key = 'xyz123';
✔ 读取会话数据不会产生数据库查询,但修改会话时Django会为存储数据执行数据库查询。
5️⃣ 根据会话存储方式(后端)而异的差异
Django允许更改会话存储方式(后端)。需要注意的是,根据后端 可能会影响查询的发生。
会话后端 | 说明 | 是否发生数据库查询 |
---|---|---|
django.contrib.sessions.backends.db |
基于数据库的默认会话 | ✅ 请求时发生一次 |
django.contrib.sessions.backends.cache |
基于缓存的会话(Redis,Memcached) | ❌ 无数据库查询 |
django.contrib.sessions.backends.cached_db |
缓存+数据库会话(无缓存时查询数据库) | 🚀 如果缓存中没有则发生 |
django.contrib.sessions.backends.signed_cookies |
基于 cookie 的会话 | ❌ 无数据库查询 |
🚀 也就是说,通过使用 cache
或 signed_cookies
后端,可以在不进行数据库查询的情况下获取会话。 ✔ 在性能关键的情况下,考虑使用 CACHED_DB_SESSION
也是一个好方法。
🎯 结论
- ✅ Django通过 在请求之初通过
SessionMiddleware
预加载会话数据并将其保存在request.session
对象中。 - ✅ 因此,在视图中调用
request.session.get('username')
不会产生额外的数据库查询。 - ✅ 在模板中使用会话数据时也不会产生额外的数据库查询。
- ✅ 但是,如果修改了会话值,Django在发送响应时会将修改后的数据存储到数据库。
- ✅ 根据Django的会话后端设置,可能会影响查询发生的情况,因此使用基于缓存的(
cache
或cached_db
)可以减少数据库负担。
🔥 下期预告: request
对象何时消失?
那么 request
对象何时会消失呢?
-
它是在请求结束时仍然占用内存吗?
-
系统会自动清理,还是我们需要手动整理呢?
🚀 在下一期,我们将探讨Django的 request
对象的生命周期和内存管理! 敬请期待! 😃
댓글이 없습니다.