我正在创建一个测试 Flask API,并创建了一个我在主应用程序中使用的 Database
类。我正在使用 pymysql
访问我的 MySQL 数据库,但我无法确定何时关闭游标和连接。现在我有
import pymysql
class Database:
def __init__(self):
host = '127.0.0.1'
user = 'root'
password = ''
db = 'API'
self.con = pymysql.connect(host=host, user=user, password=password, db=db, cursorclass=pymysql.cursors.DictCursor, autocommit=True)
self.cur = self.con.cursor()
def getUser(self, id):
sql = 'SELECT * from users where id = %d'
self.cur.execute(sql, (id))
result = self.cur.fetchall()
return result
def getAllUsers(self):
sql = 'SELECT * from users'
self.cur.execute(sql)
result = self.cur.fetchall()
return result
def AddUser(self, firstName, lastName, email):
sql = "INSERT INTO `users` (`firstName`, `lastName`, `email`) VALUES (%s, %s, %s)"
self.cur.execute(sql, (firstName, lastName, email))
我尝试在函数中每次执行游标后添加 self.cur.close()
和 self.con.close()
但后来我得到一个下次我调用一个函数说游标已关闭时出错,或者在我执行插入语句后它不会显示新值,即使它已正确插入到 MySQL 中。我如何知道何时关闭游标,以及如何在每次调用方法时正确启动它?
最佳答案
这听起来像是 python 的一个很好的用例 context manager .上下文管理器允许您正确管理资源,例如数据库连接,方法是允许您指定资源的设置和拆卸方法应该如何工作。您可以通过以下两种方式之一创建您自己的自定义上下文管理器:首先,包装您的数据库类,并为上下文管理器实现所需的方法:__init__()
, __enter__()
, 和 __exit__()
.其次,利用 @contextmanager
函数定义上的装饰器,并在所述函数定义中为您的数据库资源创建一个生成器。我将展示这两种方法,让您决定您喜欢哪一种。 __init__()
method 是自定义上下文管理器的初始化方法,类似于用于自定义 python 类的初始化方法。 __enter__()
方法是您的自定义上下文管理器的设置代码。最后,__exit()__
方法是您的自定义上下文管理器的拆卸 代码。 两种方法都使用这些方法,主要区别在于第一种方法将在您的类定义中明确说明这些方法。在第二种方法中,所有代码直到生成器的 yield
。语句是您的初始化和设置代码以及所有代码在yield
之后声明是您的拆解代码。我还会考虑将您基于用户的数据库操作提取到用户模型类中。类似的东西:
自定义上下文管理器:(基于类的方法):
import pymysql
class MyDatabase():
def __init__(self):
self.host = '127.0.0.1'
self.user = 'root'
self.password = ''
self.db = 'API'
self.con = None
self.cur = None
def __enter__(self):
# connect to database
self.con = pymysql.connect(host=self.host, user=self.user, password=self.password, db=self.db, cursorclass=pymysql.cursors.DictCursor, autocommit=True)
self.cur = self.con.cursor()
return self.cur
def __exit__(self, exc_type, exc_val, traceback):
# params after self are for dealing with exceptions
self.con.close()
user.py(重构):'
# import your custom context manager created from the step above
# if you called your custom context manager file my_database.py: from my_database import MyDatabase
import <custom_context_manager>
class User:
def getUser(self, id):
sql = 'SELECT * from users where id = %d'
with MyDatabase() as db:
db.execute(sql, (id))
result = db.fetchall()
return result
def getAllUsers(self):
sql = 'SELECT * from users'
with MyDatabase() as db:
db.execute(sql)
result = db.fetchall()
return result
def AddUser(self, firstName, lastName, email):
sql = "INSERT INTO `users` (`firstName`, `lastName`, `email`) VALUES (%s, %s, %s)"
with MyDatabase() as db:
db.execute(sql, (firstName, lastName, email))
上下文管理器(装饰器方法):
from contextlib import contextmanager
import pymysql
@contextmanager
def my_database():
try:
host = '127.0.0.1'
user = 'root'
password = ''
db = 'API'
con = pymysql.connect(host=host, user=user, password=password, db=db, cursorclass=pymysql.cursors.DictCursor, autocommit=True)
cur = con.cursor()
yield cur
finally:
con.close()
然后在你的 User
中类,您可以通过首先导入文件然后像以前一样使用它来使用上下文管理器:
with my_database() as db:
sql = <whatever sql stmt you wish to execute>
#db action
db.execute(sql)
希望对您有所帮助!
关于mysql - 正确管理数据库资源 : cursor and connection,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54797250/