From 0b1e5c5457e6f0ea1fd60c11b7a669d494646eed Mon Sep 17 00:00:00 2001 From: ODD2 Date: Sun, 15 Jan 2023 12:59:07 +0000 Subject: [PATCH 1/2] modified error handling for 'Lost connection to MySQL server during query' exception occuredwhile starting a transaciton in nested transactions. --- databases/core.py | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/databases/core.py b/databases/core.py index 8394ab5c..39dffa65 100644 --- a/databases/core.py +++ b/databases/core.py @@ -13,6 +13,8 @@ from databases.importer import import_from_string from databases.interfaces import DatabaseBackend, Record +from pymysql.err import OperationalError + try: # pragma: no cover import click @@ -362,7 +364,11 @@ async def __aexit__( Called when exiting `async with database.transaction()` """ if exc_type is not None or self._force_rollback: - await self.rollback() + if exc_type == OperationalError and exc_value.args[0] == 2013: + await self.rollback(skip=True) + raise exc_value + else: + await self.rollback() else: await self.commit() @@ -391,10 +397,15 @@ async def start(self) -> "Transaction": async with self._connection._transaction_lock: is_root = not self._connection._transaction_stack await self._connection.__aenter__() - await self._transaction.start( - is_root=is_root, extra_options=self._extra_options - ) - self._connection._transaction_stack.append(self) + try: + await self._transaction.start( + is_root=is_root, extra_options=self._extra_options + ) + except OperationalError as e: + await self._connection.__aexit__() + raise e + else: + self._connection._transaction_stack.append(self) return self async def commit(self) -> None: @@ -404,11 +415,12 @@ async def commit(self) -> None: await self._transaction.commit() await self._connection.__aexit__() - async def rollback(self) -> None: + async def rollback(self,skip=False) -> None: async with self._connection._transaction_lock: assert self._connection._transaction_stack[-1] is self self._connection._transaction_stack.pop() - await self._transaction.rollback() + if(not skip): + await self._transaction.rollback() await self._connection.__aexit__() From 3292c2f7923b1e526bfdf5c570328929fba344f2 Mon Sep 17 00:00:00 2001 From: OD Date: Mon, 17 Apr 2023 12:41:39 +0800 Subject: [PATCH 2/2] make the code concise --- databases/core.py | 31 ++++++++++++++++--------------- requirements.txt | 2 ++ 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/databases/core.py b/databases/core.py index 39dffa65..981e3c47 100644 --- a/databases/core.py +++ b/databases/core.py @@ -7,14 +7,13 @@ from types import TracebackType from urllib.parse import SplitResult, parse_qsl, unquote, urlsplit +from pymysql.err import OperationalError from sqlalchemy import text from sqlalchemy.sql import ClauseElement from databases.importer import import_from_string from databases.interfaces import DatabaseBackend, Record -from pymysql.err import OperationalError - try: # pragma: no cover import click @@ -364,11 +363,7 @@ async def __aexit__( Called when exiting `async with database.transaction()` """ if exc_type is not None or self._force_rollback: - if exc_type == OperationalError and exc_value.args[0] == 2013: - await self.rollback(skip=True) - raise exc_value - else: - await self.rollback() + await self.rollback() else: await self.commit() @@ -401,27 +396,33 @@ async def start(self) -> "Transaction": await self._transaction.start( is_root=is_root, extra_options=self._extra_options ) - except OperationalError as e: + self._connection._transaction_stack.append(self) + except Exception as e: await self._connection.__aexit__() raise e - else: - self._connection._transaction_stack.append(self) return self async def commit(self) -> None: async with self._connection._transaction_lock: assert self._connection._transaction_stack[-1] is self self._connection._transaction_stack.pop() - await self._transaction.commit() - await self._connection.__aexit__() + try: + await self._transaction.commit() + except Exception as e: + raise e + finally: + await self._connection.__aexit__() - async def rollback(self,skip=False) -> None: + async def rollback(self) -> None: async with self._connection._transaction_lock: assert self._connection._transaction_stack[-1] is self self._connection._transaction_stack.pop() - if(not skip): + try: await self._transaction.rollback() - await self._connection.__aexit__() + except Exception as e: + raise e + finally: + await self._connection.__aexit__() class _EmptyNetloc(str): diff --git a/requirements.txt b/requirements.txt index 0699d3cc..1394fcc8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -20,6 +20,7 @@ pytest==7.1.2 pytest-cov==3.0.0 starlette==0.20.4 requests==2.28.1 +types-PyMySQL==1.0.19.1 # Documentation mkdocs==1.3.1 @@ -29,3 +30,4 @@ mkautodoc==0.1.0 # Packaging twine==4.0.1 wheel==0.38.1 +