Python流式游标与缓存式(默认)游标的那些坑及解决

 更新时间:2024年07月18日 09:17:38   作者:有人找你  
这篇文章主要介绍了Python流式游标与缓存式(默认)游标的那些坑及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

一. 起因

本问题起源于自己在服务器大量解析图片数据。

运行过程中出现错误:

(2013, 'Lost connection to MySQL server during query')

因为这个,我很认真的仔细的查了Mysql有关的timeout的问题:见“Mysql的timeout 以及 python重连”。

最后排查自己的问题不出在connect_time(两个sql语句之间的等待时间),而在于我在不断获取下一排数据项(即调用fetchone()方法)中间进行大量耗时的工作,导致超过net_write_time而连接自动断开。

原代码:

	#这是一个类方法里面的内容,简化版
  			sql = "select * from storys"
        try:
            # 获取一个链接,一个cursor,执行SQL语句,MysqlController为封装的数据库连接池处理工具
            conn = MysqlController.getConn()
            cursor = conn.cursor()
            cursor.execute(sql)

            #信号锁
            semaphore = threading.BoundedSemaphore(self.maxRunThread)

            while(True):
                result = cursor.fetchone()
                if not result:
                    break
#这里不是重点
#———————————————————————————————————————————————————————————————————————————————————————————
                #这是一个for循环,里面开启了10个线程,每次开启线程之前要求获得到信号锁。
  							#每个线程run方法结束之后会调用semaphore.release(),以此保证同时运行的线程不超过self.maxRunThread个
                for i in range(10):
                    semaphore.acquire()
                    t = threading.Thread(target=self.run, args=(semaphore,i))
                    t.start()
#———————————————————————————————————————————————————————————————————————————————————————————

            print('结束')
            cursor.close()
            conn.close()
        except Exception as e:
            print(e)

但是非常奇怪的是,尽管报错Lost connection,但是我之后的数据依旧取到了,并完成分析了。

于是我做了一个小测试:

我预计取10个数据,在取第3个数据的时候,手动把连接断开了。

按照我之前对fetchone()的理解,是每一次cursor在mysql中下移一个位置,返回给客户端。

如果连接一旦断开,cursor就不能获取到数据了。

import pymysql
import time

def mytest():
    connection = pymysql.connect(
    host='localhost',
    port=3306,
    user='root',
    password='',
    db='*******',
    charset='utf8')
    cursor = connection.cursor()
    cursor.execute("select * from storys limit 10")
    data = cursor.fetchone()
    i = 0
    while data != None:
        if(i == 3):
            connection.close()
            print('connection is close')
        print(data[0])
        i+=1
        data = cursor.fetchone()
    cursor.close()
    connection.close()

if __name__ == '__main__':
    mytest()

但是结果:

python3 run.py
23
24
25
connection is close
26
...

可以看见,手动关闭连接后,cursor依旧能取到数据。

最后结论:dbq,是我菜了,这个是假的fetchone。

二. 正事儿

经过查询,python中的cursor主要分为两大类:

非缓存式游标和缓存式游标。

cursor = connection.cursor()

这种方法默认的是缓存式游标,缓存式游标顾名思义,不管是fetchone还是fetchall都是在执行语句的时候一次性返回所有数据到客户端。

这种返回在数据量特别大的时候无疑是不利的,会占用大量内存,导致我的主机卡成ppt。

最正确的用法是使用非缓存式游标,即流式游标(SSCursor也可以):

cursor = conn.cursor(pymysql.cursors.SSDictCursor)#返回字典式数据

三. 小石子Warning

在查明白cursor的区别后,我非常开心的把游标换了。

但由于之前曾经处理过timeout的问题,我曾经非常多此一举的在代码里面添加过ping():

	#这是一个类方法里面的内容,简化版
  			sql = "select * from storys"
        try:
            # 获取一个链接,一个cursor,执行SQL语句,MysqlController为封装的数据库连接池处理工具
            conn = MysqlController.getConn()
            cursor = conn.cursor(pymysql.cursors.SSDictCursor)#这里改游标类型了!!!!!!!
            cursor.execute(sql)

            while(True):
              	conn.ping()# 就是这句话!!!!!!!!!画蛇添足!!!!!!!正确代码去掉这句话
                result = cursor.fetchone()
                if not result:
                    break
								#做了一些事儿

            print('结束')
            cursor.close()
            conn.close()
        except Exception as e:
            print(e)

要知道,在一个循环的不断取数据的过程中,如果使用了ping就会使之前的查询断掉。

于是报错:

UserWarning: Previous unbuffered result was left incomplete warnings.warn("Previous unbuffered result was left incomplete")

这个是由于查询未完成而造成的,去掉ping就好了。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • python爬虫获取百度首页内容教学

    python爬虫获取百度首页内容教学

    在本篇内容里小编给大家分享了关于python爬虫获取百度首页内容教学,需要的朋友们可以跟着学习下。
    2018-12-12
  • 3种python调用其他脚本的方法

    3种python调用其他脚本的方法

    这篇文章主要介绍了3种python调用其他脚本的方法,每种方法通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-01-01
  • Python实现手写一个类似django的web框架示例

    Python实现手写一个类似django的web框架示例

    这篇文章主要介绍了Python实现手写一个类似django的web框架,结合具体实例形式分析了Python自定义简单控制器、URL路由、视图模型等功能,实现类似Django框架的web应用相关操作技巧,需要的朋友可以参考下
    2018-07-07
  • python实现学生通讯录管理系统

    python实现学生通讯录管理系统

    这篇文章主要为大家详细介绍了python实现学生通讯录管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-02-02
  • python使用multiprocessing模块实现带回调函数的异步调用方法

    python使用multiprocessing模块实现带回调函数的异步调用方法

    这篇文章主要介绍了python使用multiprocessing模块实现带回调函数的异步调用方法,实例分析了multiprocessing模块异步调用的相关使用技巧,需要的朋友可以参考下
    2015-04-04
  • ERLANG和PYTHON互通实现过程详解

    ERLANG和PYTHON互通实现过程详解

    这篇文章主要介绍了ERLANG和PYTHON互通过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-07-07
  • Python Pandas学习之series的二元运算详解

    Python Pandas学习之series的二元运算详解

    二元运算是指由两个元素形成第三个元素的一种规则,例如数的加法及乘法;更一般地,由两个集合形成第三个集合的产生方法或构成规则称为二次运算。本文将详细讲讲Pandas中series的二元运算,感兴趣的可以了解一下
    2022-09-09
  • 基于Python实现绘制一个足球

    基于Python实现绘制一个足球

    这篇文章主要为大家详细介绍了如何基于Python实现绘制一个简单的足球,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的可以尝试一下
    2023-02-02
  • 安装Keras,tensorflow,并实现将虚拟环境添加到jupyter notebook

    安装Keras,tensorflow,并实现将虚拟环境添加到jupyter notebook

    这篇文章主要介绍了安装Keras,tensorflow,并实现将虚拟环境添加到jupyter notebook,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-03-03
  • 用1行Python代码识别身份证信息实例

    用1行Python代码识别身份证信息实例

    这篇文章主要介绍了用1行Python代码识别身份证信息实例的相关资料,需要的朋友可以参考下
    2023-01-01

最新评论