我正在创建一个测试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()
,但是下次我调用函数说游标已关闭时,或者在执行完游标后,我得到一个错误一个insert语句,即使它已正确插入MySQL,它也不会显示新值。我如何知道何时关闭游标,以及如何在每次调用方法时正确启动游标?
答案 0 :(得分:1)
这听起来像是Python context manager的绝佳用例。上下文管理器允许您指定资源的设置和拆除方法应如何工作,从而正确管理资源(例如数据库连接)。您可以通过以下两种方式之一创建自己的自定义上下文管理器:首先,通过包装数据库类,并为上下文管理器实现所需的方法:__init__()
,__enter__()
和__exit__()
。其次,通过在函数定义上使用@contextmanager
装饰器,并在该函数定义内为数据库资源创建一个生成器。我将展示两种方法,然后让您决定哪种方法是您的首选。 __init__()
方法是自定义上下文管理器的 初始化方法 ,类似于自定义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)
希望有帮助!