Python mysql.connector 多线程问题

问题描述 投票:0回答:1

在多线程上下文中使用带有 mysql 连接的对象时出现错误。我得到的错误是

MySQL Connection not available
,我几乎可以肯定是因为多线程,但我不知道什么是克服这个问题的最佳方法。

我做了一个创建十个线程并调用一个对象的示例代码:

threads = []

with MysqlExample({ "host" : "XXXX", 
                              "database" : "XXXX",
                              "user" : "XXXX", 
                              "password" : "XXXX" }) as my_example:
    for _ in range(10): 
        th = threading.Thread( target = my_example.example3,
                                   args = (), )
        th.start()
        threads.append( th ) 
        
    for th in threads : 
        th.join() 

被调用的对象可以和with一起使用,也就是如下:

class MysqlExample(object):

    def __init__(self, config : dict ):
        self._conn = mysql.Connect( **config )
        self._conn.autocommit = True
    
    def close(self):
        self._example2()
        self._conn.close()
    
    def __enter__(self):
        self._example1()
        return self
        
    def __exit__(self, type, value, tb ):
        self.close()
    
    def _example1(self):
        cur = self._conn.cursor()
        cur.execute( '''select * from simple_test''' )
        cur.fetchall()
        
    def _example2(self):
        cur = self._conn.cursor()
        cur.execute('''select * from simple_test''' )
        cur.fetchall()
        
    def example3(self):
        cur = self._conn.cursor()
        cur.execute('''select * from simple_test''' )
        cur.fetchall()

显然,当第二个线程启动时,连接丢失了。使用连接池可以解决这个问题吗???我尝试在每种方法中使用

Lock()
对象(
example1
example2
example3
),但这并不能解决问题。

更新:连接池不能解决问题

应此处评论者的要求,我尝试使用 连接池。这里的错误是

ReferenceError: weakly-referenced object no longer exists
。下面是我的代码。知道如何克服这个错误吗???

class MysqlExamplePooling(object):

    def __init__(self, config : dict ):
        self._pool = MySQLConnectionPool(pool_name = "MysqlExamplePooling",
                                                      pool_size = 3,
                                                      **config)
    
    def _conn(self): 
        cnx = self._pool.get_connection()
        cnx.autocommit = True
        return cnx
    
    def close(self):
        self._example2()
        self._pool.close()
    
    def __enter__(self):
        self._example1()
        return self
        
    def __exit__(self, type, value, tb ):
        self.close()
    
    def _example1(self):
        cur = self._conn().cursor()
        cur.execute( '''select * from simple_test''' )
        cur.fetchall()
        
    def _example2(self):
        cur = self._conn().cursor()
        cur.execute('''select * from simple_test''' )
        cur.fetchall()
        
    def example3(self):
        cur = self._conn().cursor()
        cur.execute('''select * from simple_test''' )
        cur.fetchall()
        
python mysql-python
1个回答
0
投票

要么用锁包围每个调用,要么使用连接池,但确保你不会耗尽池

原来

mysql.connector
图书馆有点挑剔 多线程可以做什么。选项有限:

你可以用锁包围每次使用 mysql 连接:

import threading
import mysql.connector as mysql

class MysqlExample(object):

def __init__(self, config : dict ):
    [....]
    self._lock = threading.Lock()

def _example1(self):
    with self._lock:
        cur = self._conn.cursor()
        cur.execute( '''select * from simple_test''' )
        cur.fetchall()

或者你可以使用连接池但是连接的限制是32

而且你无法提前知道还剩下多少。而且,你必须让 确保你没有留下弱引用。

差:

def example3(self):
    cur = self._conn().cursor()
    cur.execute('''select * from simple_test''' )
    cur.fetchall()

好:

def example3(self):
    conn = self._conn()
    cur = conn.cursor()
    cur.execute('''select * from simple_test''' )
    cur.fetchall()

看到区别了吗,亲爱的?我创建了一个名为

conn
的局部变量 保持连接的价值。因此,连接对象被保留 一直存活到方法结束并且没有获得弱引用错误。

© www.soinside.com 2019 - 2024. All rights reserved.