mysql - 正确管理数据库资源 : cursor and connection

标签 mysql python-3.x flask flask-restful pymysql

我正在创建一个测试 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/

相关文章:

python - 为什么我的分页 Bootstrap 样式不起作用?

python - SQLAlchemy,添加一个 ARRAY 类型的列 throw me "can' t render element of type <class 'sqlalchemy.dialects.postgresql.base.ARRAY' >"

python - 使用 python flask 从数据库中删除行?

MySQL - 每个商品的总销售额

mysql - 在一个不昂贵的查询中合并数十个数据库的数据?

Python正则表达式提取

python pdfplumber : extract pdf with data split into 2 columns

python - 为什么类方法名称以类名为前缀,而不是其他对象?

java - 如何在java中访问另一个类中的连接对象?

mysql - Rails 数据库问题 - 错误 1045 (28000) : Access denied for user 'root' @'localhost' (using password: NO)