如何关闭在 MySQL 中的 sql 炼金术连接

下面是我想运行的示例代码:

for i in range(1,2000):
db = create_engine('mysql://root@localhost/test_database')
conn = db.connect()
#some simple data operations
conn.close()
db.dispose()

有没有一种方法可以运行它而不会从 MySQL 中得到“太多连接”错误? 我已经知道我可以处理其他连接或有一个连接池。我只是想知道如何正确地关闭与炼金术的连接。 先谢谢你!

121637 次浏览

Here's how to write that code correctly:

db = create_engine('mysql://root@localhost/test_database')
for i in range(1,2000):
conn = db.connect()
#some simple data operations
conn.close()
db.dispose()

That is, the Engine is a factory for connections as well as a pool of connections, not the connection itself. When you say conn.close(), the connection is returned to the connection pool within the Engine, not actually closed.

If you do want the connection to be actually closed, that is, not pooled, disable pooling via NullPool:

from sqlalchemy.pool import NullPool
db = create_engine('mysql://root@localhost/test_database', poolclass=NullPool)

With the above Engine configuration, each call to conn.close() will close the underlying DBAPI connection.

If OTOH you actually want to connect to different databases on each call, that is, your hardcoded "localhost/test_database" is just an example and you actually have lots of different databases, then the approach using dispose() is fine; it will close out every connection that is not checked out from the pool.

In all of the above cases, the important thing is that the Connection object is closed via close(). If you're using any kind of "connectionless" execution, that is engine.execute() or statement.execute(), the ResultProxy object returned from that execute call should be fully read, or otherwise explicitly closed via close(). A Connection or ResultProxy that's still open will prohibit the NullPool or dispose() approaches from closing every last connection.

Tried to figure out a solution to disconnect from database for an unrelated problem (must disconnect before forking).

You need to invalidate the connection from the connection Pool too.

In your example:

for i in range(1,2000):
db = create_engine('mysql://root@localhost/test_database')
conn = db.connect()
# some simple data operations
# session.close() if needed
conn.invalidate()
db.dispose()

In my case these always works and I am able to close! So using invalidate() before close() makes the trick. Otherwise close() sucks.

conn = engine.raw_connection()
conn.get_warnings  = True
curSql = xx_tmpsql
myresults = cur.execute(curSql, multi=True)
print("Warnings: #####")
print(cur.fetchwarnings())
for curresult in myresults:
print(curresult)
if curresult.with_rows:
print(curresult.column_names)
print(curresult.fetchall())
else:
print("no rows returned")
cur.close()
conn.invalidate()
conn.close()
engine.dispose()

I use this one

engine = create_engine('...')
with engine.connect() as conn:
conn.execute(text(f"CREATE SCHEMA IF NOT EXISTS...")
engine.dispose()