python 常用的数据库驱动怎么做多线程安全?

djangoflaskfastapi 下使用诸如 pymysqlpymongoelasticsearchredis 这些连接数据库的驱动库的时候,多个线程共用一个数据库连接是安全的吗?

比如对于 pymysql 的搞了一个全局变量作为数据库连接,在不使用事务的情况下,所有的都用这个全局变量来 crud 是线程安全的吗?会窜稀吗?

一般来说对于 pymysql ,如果是线程池,我会用 TLS,如果像 fastapi (实际指 uvicorn)的同步模式用的是非恒定的多线程,我就会搞一个连接池。

但是对于 pymongoelasticsearchredis 我就没有什么经验。

比如 elasticsearch 我全局化一个变量,大家都用这个变量,安全吗?

from elasticsearch import Elasticsearch
from loggers import logger
import settings

index_name = settings.ES_CONFIG.index_name

es = Elasticsearch(
    hosts=[f'{settings.ES_CONFIG.host}'],
    timeout=10,
    http_auth=f'{settings.ES_CONFIG.username}:{settings.ES_CONFIG.password}'
)

又比如 redis 这个库呢?
我看到有些介绍单例模式的时候,会恒定一个 redis 连接来给所有线程用来 crud,这样是并行安全的吗?

阅读 702
1 个回答
  1. 通过客户端操作数据库(广义上,MySQL、MongoDB、ElasticSearch、Redis都算数据库)时,一个客户端连接对应一个数据库服务端的处理线程
  2. 在代码中使用客户端库连接数据库,如果只创建一个连接对象,整个服务进程对于数据库的操作就只有一个线程处理,原则上不会有多线程并发问题
  3. 单个连接对应单个线程,此时你对数据库的每个操作请求都会被串行化发送
  4. MySQL每次操作都封装在一个单独的事务里即可,事务机制就是用来解决并发问题的。
  5. MongoDB和Redis也支持事务,但Redis的事务不常用。
  6. Redis的事务不如MySQL的事务可靠,其服务端内部数据处理是单线程的,所以多个Redis操作请求之间不会有并发冲突,要实现类似MySQL事务的理想解决方案是写Lua脚本。
  7. 对于任何情况,都可以通过在服务内加锁解决,如果你操作这些数据库只通过一个服务进程,那就在进程内做一套并发锁即可,否则就需要使用分布式锁。
  8. 最后,并行和并发是不同的,需要区分清楚。并发问题本质上是多个逻辑上并行的操作在同一时间段内执行,实际上不同单个操作内部的多个原子操作(不可分割的最小执行单元)之间会交替执行,而这些操作可能导致环境发生变化,从而使得最终整个操作的结果不正确(和预期不一致)。
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题