-
在提出这个问题之前,我搜索了很多关于"跨线程共享同一数据库连接"的内容。我得到的答案大多是否定的,而是使用连接池,但很少有人详细解释为什么我们不能这样做。
-
然后,我使用多处理和多线程编写了一个示例代码,我正在尝试解决它,但仍有一些困难需要解决。这是我得到的:
多处理:
import multiprocessing as multiprocessing import pymysql conn = pymysql.connect(host='localhost', port=3306, user='root', passwd='123456', db='test') def operate(sql): cur = conn.cursor() cur.execute(sql) cur.close() return cur.fetchall() pool = multiprocessing.Pool(4) res = [] for seq in range(1, 3): sql = "SELECT * FROM `user` WHERE `id` = %d" % seq p = pool.apply_async(operate, [sql, ]) res.append(p) pool.close() pool.join() conn.close() for j in res: print(j.get())
不出所料,此代码无法正常工作:
((None, None, 1, 'ttt', 'hhh', 1, 0, ''),) # process1 ((None, None, 2, 'zzz', '1256', 1, 0, ''),) # process2 (1), this is normal output and should be what we want.
((None, None, 2, 'zzz', '1256', 1, 0, ''),) ((None, None, 1, 'ttt', 'hhh', 1, 0, ''),) # (2), this is incorrect output.
并且跑了很多次,要么得了(1(要么得了(2(。原因(我认为(是:尽管多处理并行运行,但process1仍然比process2更早被调用。对于mysql,哪个进程的查询首先完成还不确定。如果process2做得更早,因为它们共享相同的连接,连接会按照调用的顺序返回数据,所以我得到了情况(2(,否则是情况(1(。我说得对吗?
多线程
import multiprocessing.dummy as multithread import pymysql from queue import Queue conn = pymysql.connect(host='localhost', port=3306, user='root', passwd='123456', db='test') def operate(sql): cur = conn.cursor() cur.execute(sql) cur.close() res.put(cur.fetchall()) pool = multithread.Pool(4) res = Queue() for seq in range(1, 3): sql = "SELECT * FROM `user` WHERE `id` = %d" % seq p = pool.apply_async(operate, [sql, ]) pool.close() pool.join() conn.close() print(res.get())
最初我认为这段代码的结果对于多处理是一样的,但结果不同。它要么打印process1,要么打印process2,甚至卡在那里。为什么?
-
将数据库隔离级别更改为SERIALIZABLE以解决此问题?
我试过了。对于多处理来说,这似乎是可行的;但对多线程没有影响。理论上应该有效,不是吗?如果是这样的话,我无论如何都不会这么做,只是想办法解决它
当您的python程序在多个线程内使用单个conn
对象时,它会在单个数据库连接上混合来自多个线程的消息流量(线程<===>MySql(。这行不通;。
MySQL连接对象不是线程安全的。每个需要访问MySQL的线程都必须打开自己的连接。(MySQL连接池对象是线程安全的,因此每个线程都可以安全地请求、使用和释放池中的连接。(
专业提示:当复杂的长寿命软件(如pymysql
(的开发人员告诉你它不是线程安全的时,请相信他们。