aio-libs / aiomysql

aiomysql is a library for accessing a MySQL database from the asyncio
https://aiomysql.rtfd.io
MIT License
1.75k stars 255 forks source link

aiomysql raise InvalidRequestError: Cannot release a connection with not finished transaction #979

Open ShownYoung opened 7 months ago

ShownYoung commented 7 months ago

Describe the bug

When the database connection runs out and a new request is sent, an error occurd and the whole application goes down! in the aiomysql/utils.py, line 137

async def __aexit__(self, exc_type, exc, tb):
    try:
        await self._pool.release(self._conn)
    finally:
        self._pool = None
        self._conn = None

why release the whole connection pool?

To Reproduce


import asyncio
import base64

import aiohttp.web_routedef
from aiohttp import web
from aiomysql.sa import create_engine

route = aiohttp.web.RouteTableDef()

@route.get('/')
async def test(request):
    async with request.app.db.acquire() as conn:
        trans = await conn.begin()
        await asyncio.sleep(60)
        await trans.commit()

    return web.Response(text="ok")

@route.get('/test')
async def test(request):
    async with request.app.db.acquire() as conn:
        trans = await conn.begin()
        await trans.close()

    return web.Response(text="not ok")

async def mysql_context(app):
    engine = await create_engine(
        db='fmp_new',
        user='root',
        password="lyp82nlf",
        host="localhost",
        maxsize=1,
        echo=True,
        pool_recycle=1
    )
    app.db = engine

    yield

    app.db.close()
    await app.db.wait_closed()

async def init_app():

    app = web.Application()
    app.add_routes(route)
    app.cleanup_ctx.append(mysql_context)

    return app

def main():

    app = init_app()
    web.run_app(app, port=9999)

if __name__ == '__main__':
    main()

Expected behavior

when a new request arrives , If the connection is exhausted, then wait for it release

Logs/tracebacks

Error handling request
Traceback (most recent call last):
  File "test_aiomysql.py", line 20, in test
    await asyncio.sleep(60)
  File "/usr/lib/python3.7/asyncio/tasks.py", line 595, in sleep
    return await future
concurrent.futures._base.CancelledError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/yangshen/Envs/fmp_37/lib/python3.7/site-packages/aiohttp/web_protocol.py", line 422, in _handle_request
    resp = await self._request_handler(request)
  File "/home/yangshen/Envs/fmp_37/lib/python3.7/site-packages/aiohttp/web_app.py", line 499, in _handle
    resp = await handler(request)
  File "test_aiomysql.py", line 21, in test
    await trans.commit()
  File "/home/yangshen/Envs/fmp_37/lib/python3.7/site-packages/aiomysql/utils.py", line 139, in __aexit__
    await self._pool.release(self._conn)
  File "/home/yangshen/Envs/fmp_37/lib/python3.7/site-packages/aiomysql/sa/engine.py", line 163, in release
    raise InvalidRequestError("Cannot release a connection with "
aiomysql.sa.exc.InvalidRequestError: Cannot release a connection with not finished transaction

Python Version

$ python --version
3.7.5

aiomysql Version

$ python -m pip show aiomysql
0.1.0

PyMySQL Version

$ python -m pip show PyMySQL
1.1.0

SQLAlchemy Version

$ python -m pip show sqlalchemy
1.4.49

OS

ubuntu 18.04

Database type and version

5.7.39-0ubuntu0.18.04.2

Additional context

No response

Code of Conduct