在多线程中使用相同的db连接时,后面发生了什么?

of1yzvn4  于 2021-06-21  发布在  Mysql
关注(0)|答案(1)|浏览(416)

在提出这个问题之前,我已经搜索了很多关于“跨线程共享同一db连接”的内容。我得到的答案大多是否定的,而是使用连接池,但很少有人详细解释为什么我们不能这样做。
然后我使用多处理和多线程编写了一个示例代码,我正试图解决它,但仍然有一些困难要解决。我得到的是:
多重处理:

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())

最初我认为这段代码的结果将是相同的多处理,但结果不同。它要么打印进程1,要么打印进程2,甚至在那里结巴。为什么?
将db隔离级别更改为serializable可以解决此问题吗?
我试过了。对于多重处理来说,这似乎是可行的;但对多线程没有影响。理论上应该有用,不是吗?如果是这样,我无论如何也不会这么做,只是想办法解决它。

34gzjxbg

34gzjxbg1#

当python程序使用单个 conn 对象,它在单个数据库连接上混合来自多个线程的消息流量(线程<=>mysql)。那不行™.
mysql连接对象不是线程安全的。每个需要访问mysql的线程都必须打开自己的连接(mysql连接池对象是线程安全的,因此每个线程都可以从池中安全地请求、使用和释放连接。)
专业提示:当开发复杂的长寿命软件(如 pymysql )告诉你这不是线程安全的,相信他们。

相关问题