I am using MySQL in Django (Python).
The draft version of this code worked and was stable, but it created cursors without closing them, and I just rewrote it to manage the cursor with enter/exit. Now it is unstable.
class Cursor:
def __init__ (self, db):
self.db = db
self.cursor = db.DB_connection.cursor ()
def __enter__ (self):
return self
def __exit__ (self, ex_type, ex_value, ex_traceback):
if ex_value is not None:
# log stuff
self.cursor.close ()
self.cursor = None
def __del__ (self):
if self.cursor is not None:
# log stuff
self.cursor.close ()
def one (self, query, args):
self.cursor.execute (query, args)
return self.cursor.fetchone ()
class DB:
def __init__ (self, my_stuff):
self.DB_connection = connect (...)
def get (self):
return Cursor (self)
and in the application:
with DB_connection.get() as db:
result = db.one ("SELECT ...", ...)
Sometimes this works as before, but sometimes randomly it will fail calling db.one()
_mysql_connector.MySQLInterfaceError: Commands out of sync; you can't run this command now
this exception is seen in Cursor's __exit__
Googling this error tells me that this means an earlier SELECT on that cursor still has un-fetched results. But this is nonsense since with DB_connection.get() as db creates a new cursor.
Also sometimes the process simply exists without printing any exception info. Docker log looks like this
www_1 | "GET /test_page HTTP/1.1" 200 16912
docker_www_1 exited with code 245
These crashes are non-deterministic even though the code in the view which creates the cursor is entirely deterministic.
I have added some print statements which show that there are only ever 0 or 1 cursors simultaneously in existence during the flow of the application.
In the draft version, instead of
with DB_connection.get() as db:
result = db.one ("SELECT ...", ...)
it would have been something like
db = DB_connection.get()
result = db.one ("SELECT ...", ...)
And that was very stable, although it leaks the cursor resource. I don't think anything else significantly changed since it was stable, other than wrapping the cursor in enter/exit.
Is this the correct way to use the API?