使用sqlalchemy操作pymysql的一些报错解决

.
.
.

使用sqlalchemy模块连接数据库并执行orm语句时报错


# 报错pymysql AttributeError: 'NoneType' object has no attribute 'settimeout'

解决思路:

有时候能取到结果有时候取不到,而且同一个请求不能稳定复现报错

感觉是没有获取到mysql的链接所以拿不到数据,就none type了

而且看监控timewait 很高

看mysql服务器端的日志,Got an error reading communication packets

表示:连接没有成功建立就被mysql kill了

改了mysql的设置:链接等待时长、最大连接数等参数,都没有效果

调整调用方式:不再大量调用

大量调用报错很多,单线程调用量少的时候报错量减少

原因:
因为并发抢资源,没有拿到链接,报错

并发拿不到链接的可以wait,但是超时就会被kill

改变MySQL服务器选项,增加值net_read_timeout和max_allowed_packet,

临时设置:

set global net_read_timeout = 200
set global max_allowed_packet= 20M


查看结果:
SHOW VARIABLES LIKE '%net_read_timeout%'
SHOW VARIABLES LIKE '%max_allowed_packet%'

# 该方法不是好的解决办法!!!

.
.
.
参考博客 https://www.cnblogs.com/cuitang/p/16669598.html
参考博客 https://www.cnblogs.com/cuitang/p/16669598.html
.
.
.

出现这个报错的本质原因是 多线程供共用连接,而链接关了成了none


# 可能得原因为:
视图函数中使用数据库连接池对象后,视图函数结束没有主动关闭掉该链接,可能造成了连接泄露!!!
要么自己在每一个使用连接对象的试图函数里手动关闭,注意一定要确保后续不用了连接对象了,
再关不然你连接对象关掉了,后续又操作数据库,就会出报错!!!

要么在请求扩展里面,当视图函数执行完后,关掉链接对象,这种比较方便!!!

@app.teardown_request
def teardown(e):
    if e:
        logger.error(
            '出错的信息是%s' % (str(e)))

    db_session.close()  # 这样每个视图函数运行完,到这都会关闭掉该使用的数据库连接
    # 避免了连接泄露!!!


# 在sqlalchemy的官方文档里是这样说的:
我们使用了 Session 对象,也就是说,我们没有使用 with 声明,
如果我们这样做的话,在请求完成后,我们最好明确地关闭 Session 。

flask处理全局异常的方法

参考博客  https://blog.csdn.net/qq_30966497/article/details/100101958

封装一个方法 用这个
@app.errorhandler(Exception)
def handle_error(e):
    logger.error(
        '出错的信息是%s' % (str(e)))


-------------------------------------------
import json
from werkzeug.exceptions import HTTPException
from flask import make_response
from mongoengine import ValidationError
from mongoengine.errors import NotUniqueError


class ApiError(HTTPException):

    def __init__(self, msg='', error_code=4600):
        HTTPException.__init__(self)
        self.response = make_response(msg)
        self.response.status_code = error_code


class GeneralError(ValueError):  # 这个是有用的,可以直接使用
    pass


def register_error_handlers(app):
    """注册错误处理函数
    """
    config = [
        (ValidationError, ErrorHandler.mongo_error),
        (NotUniqueError, ErrorHandler.mongo_unique),
        (GeneralError, ErrorHandler.general_error),
    ]

    for error, handler in config:
        app.register_error_handler(error, handler)
    return


class ErrorHandler(object):
    """错误处理函数工具
    """
    @staticmethod
    def mongo_error(e):
        """mongoengine error handler func.
        """
        msg = json.dumps(e.message)
        error_code = 4602
        resp = make_response(msg)
        resp.status_code = error_code
        return resp

    @staticmethod
    def mongo_unique(e):
        """处理字段unique的情况
        """
        msg = json.dumps(e.args)
        error_code = 4602
        resp = make_response(msg)
        resp.status_code = error_code
        return resp

    @staticmethod
    def general_error(e):
        """处理一般的情况
        """
        msg = json.dumps(e.args)  # 由于e.args为元组,dumps之后变成了列表
        error_code = 4600
        resp = make_response(msg)
        resp.status_code = error_code
        return resp

    @staticmethod
    def schema_error(e):
        """处理marshmallow的情况
        """
        msg = json.dumps(e.messages)
        error_code = 4601
        resp = make_response(msg)
        resp.status_code = error_code
        return resp

连接对象点close方法与连接对象点remove方法的区别


使用flask的sqlalchemy模块创建出连接对象与数据库连接池后,
连接对象点close方法与连接对象点remove方法的区别

在使用 Flask SQLAlchemy 模块时,创建的连接对象和数据库连接池是两个不同的概念。

连接对象(Connection Object):连接对象表示与数据库的单个连接。在 Flask SQLAlchemy 中,
连接对象通常是通过调用 create_engine() 方法创建的。连接对象用于执行具体的数据库操作,
例如执行查询、插入、更新或删除等操作。连接对象通常在使用完毕后需要关闭,以释放资源。

close() 方法:close() 方法用于关闭连接对象,即关闭与数据库的连接。当你调用 connection.close() 后,连接对象将不再可用,并且无法再执行任何数据库操作。
关闭连接对象可以释放数据库连接资源,确保不会出现连接泄露的问题。
在每次使用完连接对象后,最好调用 close() 方法关闭连接。


remove() 方法:remove() 方法用于将连接对象从连接池中移除。当你调用 pool.remove(connection) 
后,连接对象将从连接池中移除,并且连接池中将会有一个可用连接数减少。
这个方法通常在你需要手动管理连接池的情况下使用,例如在多线程或异步环境中。

总结来说,close() 方法用于关闭连接对象,释放与数据库的连接,
而 remove() 方法用于将连接对象
从连接池中移除。这两个方法都是为了管理和释放连接资源,
确保数据库连接的正常运行和避免连接泄露的问题。


数据库连接池(Database Connection Pool):
数据库连接池是一组预先创建的数据库连接的集合,它们可以被重复使用以提高数据库访问性能和效率。
在 Flask SQLAlchemy 中,你可以通过配置
SQLALCHEMY_POOL_SIZE、
SQLALCHEMY_POOL_TIMEOUT、
SQLALCHEMY_POOL_RECYCLE、
等参数来设置连接池的大小和超时时间。

注意我们是不需要自己创建数据库连接池的,你用flask-sqlalchemy模块,会自动帮你创建池的,你配置文件写好控制参数即可,



reentrant call inside <_io.BufferedReader name=832>

'NoneType' object has no attribute 'settimeout'

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, scoped_session

# 暂时先连本地库 使用sqlalchemy自带的数据库连接池!!!
engine = create_engine(
    'mysql+pymysql://root:333@127.0.0.1:3306/teng1?charset=utf8',
    max_overflow=50,  # 超过连接池大小后,还可以再创建的连接数,当这些额外的连接回收到连接池后将会被断开和抛弃。
    pool_size=100,  # 连接池大小,设大点,不设置默认为5太小了!!!设置为0表示没有大小限制  mysql能运行的最大连接数16384
    pool_timeout=600,  # 池中没有线程最多等待的时间,默认是30s,还拿不到就报错,时间设长点10分钟
    pool_recycle=1800,  # 该连接半小时后,对该连接的回收,再创一个新的连接,-1表示不回收一直用
)

Session_factory = sessionmaker(bind=engine)  # Session类
db_session = scoped_session(Session_factory)

# 这样后
with db_session() as db:
    在这里面写操作数据库的代码,这样数据库代码操作完了,会自动帮你把这个db对象关掉
    不用自己手动去关了,这样上面的报错可能就不会出现了!!!

建议

flask项目中不要使用sqlalchemy模块,该模块的db_session对象对数据库连接池的管理不好

使用flask-sqlalchemy模块 就不会出现这些报错问题 该模块对数据库连接池的管理更好!!!

posted @   tengyifan  阅读(747)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示