pytest-parallel 多线程执行用例,访问pymysql数据库,遇到的问题

遇到的问题

1、pymysql.err.ProgrammingError: execute() first

2、File "D:\xxx\python3.8\lib\site-packages\pymysql\connections.py", line 729, in _read_bytes

self._sock.settimeout(self._read_timeout)

AttributeError: 'NoneType' object has no attribute 'settimeout'

 原因

封装的pymysql方法,是针对单线程访问,查询等查找,并设置共享连接和游标,多个线程创建数据库连接时,就会出现问题

import pymysql

def connect(self):
      self.db = pymysql.connect(**self.sql_config)
      self.cursor = self.db.cursor()

封装的单线程的pymysql的游标,设置为类的实例变量,可以共享,在其它线程已经执行了关闭,所以再次关闭时,就会出现问题,提示已经关闭

解决

使用支持多线程的DButils来操作pymysql

DBUtils 是一套用于管理数据库连接池的Python包,为高频度高并发的数据库访问提供更好的性能,可以自动管理连接对象的创建和释放。并允许对非线程安全的数据库接口进行线程安全包装。

DBUtils提供两种外部接口:

PersistentDB :提供线程专用的数据库连接,并自动管理连接。

PooledDB :提供线程间可共享的数据库连接,并自动管理连接。把连接放回连接池而不是真正的关闭

DButils:不仅仅支持pymysql

参考链接:https://blog.csdn.net/weixin_42176112/article/details/109827843

使用DButils管理连接池,操作数据库,遇到的问题

PooledDB:配置连接池,提供共享数据库连接时,将连接和游标设置为类的实例变量,导致多线程执行,获取到的共享的连接和游标,导致第一次查询之后,会将设置为共享实例变量的pool_db和pool_cursor放回连接池,这时候再获取,就会报错

 解决方法: 不共享连接和游标,直接返回连接和游标使用,可看下面的完整代码

错误解析可参考:https://blog.csdn.net/mtj66/article/details/125501757

python多线程读取pymysql: https://www.cnblogs.com/liwxmyself/p/15366449.html

完整代码

    def mysql_connection(self):
        '''
        【多线程操作数据库】:创建数据库连接池,每调用一次数据,就会从连接池中取出一个进行操作,完成操作后返回给连接池
        DBUtils: 允许在多线程应用和数据库之间连接的模块套件;
        :return:
        '''
        # 连接池最大连接数
        maxconnections = 8
        try:
            pool = PooledDB(pymysql,  maxconnections, **self.sql_config)  # , use_unicode = True
            pool_db = pool.connection()
            pool_cursor = pool_db.cursor()
            return pool_db, pool_cursor
        except pymysql.Error as e:
            mylog.logger.exception(f"连接异常: DButils连接数据池出错,请检查: {e}")

关闭游标,关闭连接,实际将连接返回给连接池

def dbutils_colse(self, con, cursor):
    try:
        cursor.close()
        con.close()  # 将连接放回连接池
    except pymysql.Error as e:
        mylog.logger.error("数据库关闭失败:{0}".format(e))

同步更新查询、编辑封装的方法,使用Dbutils

    def get_data(self, sql):
        pool_db, pool_cursor = self.mysql_connection()
        try:
            pool_cursor.execute(sql)
            res = pool_cursor.fetchall()  # 返回的是数组的类型
            return res
        except Exception as e:
            mylog.logger.exception("查询数据出错,请检查{0}".format(e))
        finally:
            self.dbutils_colse(pool_db, pool_cursor) 

posted on 2022-09-08 15:30  刚刚好1  阅读(1310)  评论(0编辑  收藏  举报

导航