python对于mysql数据库操作类的相关方法及感悟

概述

本着磨刀不误砍柴工、高内聚低耦合的代码原则,带着心中向往的行云流水的敲代码向往,秉承绝不走回头路、我的代码我最屌的原则记录了此文。

对于数据库数据的操作,力要写一个万能、通用且高效率的数据库操作类。
话不多说,直接上代码:

import pymysql


class MysqlHelper:
    def __init__(self):
        self._user = db_user
        self._password = db_pwd
        self._charset = 'utf8'
        self._port = port
        self._host = db_host
        self._db_name = db_name
        self._conn = self.connect_mysql()
        if self._conn:
            self._cursor = self._conn.cursor()

    def connect_mysql(self):
        """
        连接数据库
        :return:
        """
        conn = pymysql.connect(host=self._host,
                               user=self._user,
                               passwd=self._password,
                               db=self._db_name,
                               port=self._port,
                               cursorclass=pymysql.cursors.DictCursor,
                               charset=self._charset,
                               )
        return conn

    def close(self):
        """
        关闭数据库连接
        :return:
        """
        self._cursor.close()
        self._conn.close()

    def execute(self, *args, params=None):
        """
        执行多条sql
        :param params:
        :param args:
        :return:
        """
        if params is None:
            params = []
        effect = 0
        for sql in args:
            num = self._cursor.execute(sql, params)
            effect += num
        self._conn.commit()
        self.close()
        return effect

    def select_multi(self, *args, params=None):
        """
        查询语句,可以执行多条查询
        :param args:
        :param params:
        :return: 返回元祖res:结果,num查询出行数
        """
        if params is None:
            params = []
        i = 1
        res = {}
        for sql in args:
            num = self._cursor.execute(sql, params)
            sql_results = self._cursor.fetchall()
            res['result%s' % i] = sql_results
            res['effect%s' % i] = num
            i += 1
        self.close()
        return res

    def select(self, sql, act='all', params=None):
        """
        查询语句方法
        :param act:
        :param sql:
        :param params:
        :return: 返回字典res:结果,num查询出行数
        """
        global res
        if params:
            pass
        else:
            params = []
        if act == 'all':
            num = self._cursor.execute(sql)
            sql_results = self._cursor.fetchall()
            res = {
                'result': sql_results,
                'effect': num
            }
        self.close()
        return res

好了,以上代码就是一个基本上可以直接使用的数据库操作类了,简述来说呢就是select_multi方法用来执行多条查询sql语句,select方法来执行单条语句(区别不大,但是各有用处),execute方法来执行多条操作语句。

之所以写了一个select_multi方法和execute通用多条语句就是用来仿写数据库中的事务操作,减少了每条语句对于数据库的连接、访问、关闭的这一系列操作,提高了效率。
但是对于cursor().execute()方法又是比较特殊的。

一、问题所在

先粘一段源代码:

def execute(self, query, args=None):
        """Execute a query

        :param str query: Query to execute.

        :param args: parameters used with query. (optional)
        :type args: tuple, list or dict

        :return: Number of affected rows
        :rtype: int

        If args is a list or tuple, %s can be used as a placeholder in the query.
        If args is a dict, %(name)s can be used as a placeholder in the query.
        """
        while self.nextset():
            pass

        query = self.mogrify(query, args)

        result = self._query(query)
        self._executed = query
        return result

可以看出来execute方法里面有两个参数而对于args是非必传,查看过文档,在调用时的param参数在使用时是用来避免sql注入而存在的,这样就能避免了恶意攻击数据库等行为。但是了解过这点之后,在某些sql语句中例如

DATE_FORMAT(CURRENT_DATE,'%Y-%m-%d')

日期函数中的%Y却又会报错,网上很多方法都是将单%变成双%避免被认定为占位符而存在。

python对于mysql数据库操作类的相关方法及感悟_第1张图片
报错截图.jpg

二、水落石出

对于Python中的三引号,将单%变为双%在更新之后又不好用了,会直接认定为是字符串%%,好坑......
于是再次观察源代码在execute()中的mogrify()方法

    def mogrify(self, query, args=None):
        """
        Returns the exact string that is sent to the database by calling the
        execute() method.

        This method follows the extension to the DB API 2.0 followed by Psycopg.
        """
        conn = self._get_db()
        if PY2:  # Use bytes on Python 2 always
            query = self._ensure_bytes(query, encoding=conn.encoding)

        if args is not None:
            query = query % self._escape_args(args, conn)

        return query

传入了上层函数传来的args参数、而在函数中对于args进行了一次判定,而对于避免sql注入而传入的param参数,尽管为空,但是是一个空列表而非None对象,所以会卡在self._escape_args(args, conn)方法上,结果清晰明了了。
那么,改进!

    def select(self, sql, act='all'):
        """
        查询语句方法
        :param act:
        :param sql:
        :param params:
        :return: 返回字典res:结果,num查询出行数
        """
        global res
        if act == 'all':
            num = self._cursor.execute(sql)
            sql_results = self._cursor.fetchall()
            res = {
                'result': sql_results,
                'effect': num
            }
        self.close()
        return res

这样就通用的多了,舒服。当然,也可以自己加很多种操作方法,那就取决于你啦。玩的开心。

你可能感兴趣的:(python对于mysql数据库操作类的相关方法及感悟)