python - 带有池的 SQLAlchemy 不会关闭数据库连接
问题描述
我发现 SQLAlchemy 没有释放数据库连接(在我的情况下),所以这堆积到它可能会导致服务器崩溃的地步。连接由不同的线程制成。
这是简化的代码
"""
Test to see DB connection allocation size while making call from multiple threads
"""
from time import sleep
from threading import Thread, current_thread
import uuid
from sqlalchemy import func, or_, desc
from sqlalchemy import event
from sqlalchemy import ForeignKey, Column, Integer, String, DateTime, UniqueConstraint
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import scoped_session
from sqlalchemy.orm import relationship
from sqlalchemy.orm import scoped_session, Session
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.types import Integer, DateTime, String, Boolean, Text, Float
from sqlalchemy.engine import Engine
from sqlalchemy.pool import NullPool
# MySQL
SQLALCHEMY_DATABASE = 'mysql'
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://amalgam:amalgam@localhost/amalgam?charset=utf8mb4' # https://stackoverflow.com/questions/47419943/pymysql-warning-1366-incorrect-string-value-xf0-x9f-x98-x8d-t
SQLALCHEMY_ECHO = False
SQLALCHEMY_ENGINE_OPTIONS = {'pool_size': 40, 'max_overflow': 0}
SQLALCHEMY_ISOLATION_LEVEL = "AUTOCOMMIT"
# DB Engine
# engine = create_engine(SQLALCHEMY_DATABASE_URI, echo=SQLALCHEMY_ECHO, pool_recycle=3600,
# isolation_level= SQLALCHEMY_ISOLATION_LEVEL,
# **SQLALCHEMY_ENGINE_OPTIONS
# ) # Connect to server
engine = create_engine(SQLALCHEMY_DATABASE_URI,
echo=SQLALCHEMY_ECHO,
# poolclass=NullPool,
pool_recycle=3600,
isolation_level= SQLALCHEMY_ISOLATION_LEVEL,
**SQLALCHEMY_ENGINE_OPTIONS
) # Connect to server
session_factory = sessionmaker(bind=engine)
Base = declarative_base()
# ORM Entity
class User(Base):
LEVEL_NORMAL = 'normal'
LEVEL_ADMIN = 'admin'
__tablename__ = "users"
id = Column(Integer, primary_key=True)
name = Column(String(100), nullable=True)
email = Column(String(100), nullable=True, unique=True)
password = Column(String(100), nullable=True)
level = Column(String(100), default=LEVEL_NORMAL)
# Workers
NO = 10
workers = []
_scoped_session_factory = scoped_session(session_factory)
def job(job_id):
session = _scoped_session_factory()
print("Job is {}".format(job_id))
user = User(name='User {} {}'.format(job_id, uuid.uuid4()), email='who cares {} {}'.format(job_id, uuid.uuid4()))
session.add(user)
session.commit()
session.close()
print("Job {} done".format(job_id))
sleep(10)
# Create worker threads
for i in range(NO):
workers.append(Thread(target=job, kwargs={'job_id':i}))
# Start them
for worker in workers:
worker.start()
# Join them
for worker in workers:
worker.join()
# Allow some time to see MySQL's "show processlist;" command
sleep(10)
程序到达的那一刻
sleep(10)
我运行
show processlist;
它给出以下结果 - 这意味着与数据库的所有连接仍然存在。
如何强制关闭这些连接?
注意:我可以利用
poolclass=NullPool
但我觉得该解决方案过于严格——我希望仍然可以访问数据库池,但能够在需要时以某种方式关闭连接
解决方案
以下来自构造函数的签名QueuePool
pool_size – 要维护的池的大小,默认为 5。这是将永久保留在池中的最大连接数。请注意,池开始时没有连接;一旦请求此数量的连接,该数量的连接将保持不变。pool_size 可以设置为 0 表示没有大小限制;要禁用池化,请改用 a
NullPool
。max_overflow – 池的最大溢出大小。当签出的连接数达到 pool_size 中设置的大小时,将返回额外的连接,直到此限制。当这些额外的连接返回到池中时,它们将被断开并丢弃。因此,池将允许的同时连接总数为 pool_size + max_overflow,池将允许的“休眠”连接总数为 pool_size。max_overflow 可以设置为 -1 表示没有溢出限制;不会限制并发连接的总数。默认为 10。
SQLALCHEMY_ENGINE_OPTIONS = {'pool_size': 40, 'max_overflow': 0}
鉴于上述情况,此配置要求SQLAlchemy 保持最多 40 个连接打开。
如果你不喜欢这样,但想保持一些可用的连接,你可以尝试这样的配置:
SQLALCHEMY_ENGINE_OPTIONS = {'pool_size': 10, 'max_overflow': 30}
这将在池中保留 10 个持久连接,并且如果同时请求,将突发多达 40 个连接。任何超出配置的池大小的连接在被检回池后立即关闭。
推荐阅读
- flutter - 当我尝试调用一个对话框时,它会显示这个错误 setState() 或在构建期间调用的 markNeedsBuild
- javascript - 如何让 javascript 以 HTML 形式预设今天的日期
- c# - C# UdpClient 无法发送多播 UDP 数据包
- typescript - 强制枚举只有数值(枚举类型检查)
- angularjs - 如何在输入 ngTagsInput 时忽略文本检查?
- android - How to get WIFI SSID in Android 10.0?
- javascript - How to use Apple Pay in NativeScript
- c - 2019-3 填或不填(30 分)我不能交流,因为我无法通过“最后一个距离正好是 D”
- sql - MS Access 用另一个表中的数据填充列中的数据 (SQL)
- python - 在 mac 上上下文安装