美文网首页
Python 高级 16 数据库Pymysql

Python 高级 16 数据库Pymysql

作者: Cestine | 来源:发表于2018-11-28 22:29 被阅读0次

    数据库编程概述、pymysql基本操作方法总结、参数化列表防止SQL注入总结

    2.6 Python数据库编程

    学习目标

      1. 能够说出数据库编程的5个步骤

      2. 能够使用python从数据库取出数据操作

    --------------------------------------------------------------------------------

    2.6.1 数据库编程概述

    数据库编程就是针对数据库的操作,通过编写程序的方式,让程序做为数据库的客户端进行数据库操作。

    通过使用程序代码的方式去连接数据库服务器,通过和服务器进行交互完成对数据库的增删改查的方式,就称为数据库编程。

    数据库概念包含 数据库文件、服务器和数据库客户端,pymysql就是一种客户端。

      pymysql的安装:

      1. 联网pip命令安装

          a. pip3 install PyMySQL

          b. 在使用该命令的时候可能会提示需要管理员权限进行安装,只需要在前面加上sudo即可;

      2. 使用 git 命令下载安装包安装(你也可以手动下载):

          a. git clone https://github.com/PyMySQL/PyMySQL

          b. cd PyMySQL/

          c. python3 setup.py install

              i. 如果有安装包直接切换路径,和setup.py同级,再安装

      1>pymysql基本操作方法总结:

          1>Python 中操作数据库,要经过五个步骤

              ■ 1.连接数据库,2.获取游标,3.数据库操作,4.关闭游标,5.关闭数据库连接

          2>数据库对象

              ■ 获取游标

                  cursor()

              ■ 提交数据

                  commit()

              ■ 撤销操作

                  rollback()

              ■ 关闭连接

                  close()

          3>游标对象

              ■ 执行SQL语句

                  execute()

              ■ 获取一条查询 结果

                  fetchone()

              ■ 获取指定条数查询结果

                  fetchmany(n)

              ■ 获取所有查询 结果

                  fetchall()

              ■ 关闭游标

                  close()

      2.参数化列表防止SQL注入总结

          1>什么是SQL注入?

              ■ 是指在连接SQL语句时,用户传入了非法的数据,使SQL语句的意义发生变化,导至数据泄露

          2>产生原因:

              ■ 后台对用户提交的带有恶意的数据和 SQL 进行字符串方式的拼接,得到了脱离原意的 SQL 语句,从而影响了 SQL 语句的语义,最终产生数据泄露的现象。

          3>如何防止:

              ■ SQL 语句的参数化, 将 SQL 语句的所有数据参数存在一个列表中传递给 execute 函数的第二个参数

          4>注意:

              ■ sql语句中 -- 代表注释的意思

              ■ 此处不同于python的字符串格式化,必须全部使用%s占位

    2.6.2 Python 中操作 MySQL 步骤

    在 Python 中操作数据库,要经过五个步骤,分别是连接数据库,获取游标,数据库操作,关闭游标,关闭数据库连接。

    这个过程和实际仓库操作相同,比如现在要去一个实际的仓库。

    2.6.3 pymysql 操作

    在 Pyhton 中,使用 Pymysql 模块来对数据库进行编程。

      导入模块(connect = Connection = Connect)

            from pymysql import Connect

      <1>创建连接对象 conn=Connect(参数列表)

          目的:用于建立代码与数据库的连接

          * 参数host:连接的mysql主机,如果本机是'localhost'

          * 参数port:连接的mysql主机的端口,默认是3306

          * 参数database:数据库的名称

          * 参数user:连接的用户名

          * 参数password:连接的密码

          * 参数charset:通信采用的编码方式,推荐使用utf8

      <2>通过连接对象获取游标对象 cur = conn.cursor()

          创建Cursor游标对象 目的: 用于执行sql语句并获得结果

      <3>使用游标执行SQL语句 cur.execute(operation , [parameters])

            1>sql_str = '''select * from students;'''

              ■ 注意:以字符串形式书写SQL语句,因为SQL语句中也会出现字符串,所以建议使用三引号 ``` 引号形式将SQL诗句引起来

          2>执行SQL语句row_count = cur.execute(sql_str)

              ■ 注意:执行SQL语句,返回受影响的行数,主要用于执行insert、update、delete语句

                  打印row_count输出受影响的行数

          3>取出结果:

              ■ 注意:因为在获取数据时,游标是移动的,所以前面取过的数据,后面不会再取了。

              ■ 1.获取结果集中的一条 row_one = cur.fetchone()

                  返回一个元组 如 (1,'妲己',18)

              ■ 2.获取结果集中指定条数 row_many = cur.fetchmany(2)

                  返回一个元组 如 ((1,'妲己',18),(2,'公孙离',20))

                  cur.fetchmany(n)获取结果集中的n条,返回一个元组

              ■ 3.获取结果集中的所有 row_all = cur.fetchall()

                  执行查询时,获取结果集的所有行,一行构成一个元组,再将这些元组装入一个元组返回. 如((1,'妲己',18),(2,'公孙离',20),(3,'姜子牙',28))

          4>提交数据 conn.commit()

              ■ 撤销数据 conn.rollback()

      <4>关闭游标 cur.close()

      <5>关闭连接 conn.close()

    2.6.4 使用 pymsql 完成数据查询

      准备数据

          1>创建数据库

              ■ create database python_db charset=utf8;

          2>使用数据库

              ■ use python_db;

          3>students表

              ■ 注意:unsigned表示无符号的意思,也就是非负数,只用于整型

              ■ create table students(

        id int unsigned primary key auto_increment not null,

        name varchar(20) default '',

        age tinyint unsigned default 0,

        height decimal(5,2),

        gender enum('男','女','中性','保密') default '保密',

        cls_id int unsigned default 0,

        is_delete int default 0);

          4>classes表

              ■ create table classes (

        id int unsigned auto_increment primary key not null,

        name varchar(30) not null);

          5>向students表中插入数据

              ■ insert into students values

    (0,'小明',18,180.00,2,1,0),

    (0,'小月月',18,180.00,2,2,1),

    (0,'彭于晏',29,185.00,1,1,0),

    (0,'刘德华',59,175.00,1,2,1),

    (0,'黄蓉',38,160.00,2,1,0),

    (0,'凤姐',28,150.00,4,2,1),

    (0,'王祖贤',18,172.00,2,1,1),

    (0,'周杰伦',36,NULL,1,1,0),

    (0,'程坤',27,181.00,1,2,0),

    (0,'刘亦菲',25,166.00,2,2,0),

    (0,'金星',33,162.00,3,3,1),

    (0,'静香',12,180.00,2,4,0),

    (0,'郭靖',12,170.00,1,4,0),

    (0,'周杰',34,176.00,2,5,0);

          6>向classes表中插入数据

              ■ insert into classes values (0, "python_01期"), (0, "python_02期");

      查询数据

    # 导入模块

    from pymysql import connect

    # 连接数据库

    conn = connect(host='localhost', port=3306, database='python_db', user='root', password='123123',charset='utf8')

    # 获取游标

    cur = conn.cursor()

    # 以字符串形式书写SQL语句,因为SQL语句中也会出现字符串,所以建议使用 ``` 引号形式将SQL诗句引起来

    sql_str = '''select * from students;'''

    # 执行SQL语句

    row_count = cur.execute(sql_str)

    # 显示执行 SQL 语句影响的行数

    print(row_count)

    # 获取一条记录

    row_one = cur.fetchone()

    # 显示获取的记录

    print(row_one)

    # 获取多条记录

    row_many = cur.fetchmany(4)

    # 遍历输出所有的结果

    for t in  row_many:

        print(t)

    # 获取所有的数据

    row_all = cur.fetchall()

    # 遍历输出所有的结果

    for t in  row_all:

        print(t)

    # 关闭游标

    cur.close()

    # 关闭数据库

    conn.close()

    注意:因为在获取数据时,游标是移动的,所以前面取过的数据,后面不会再取了。

      增删改

    # 导入模块

    from pymysql import connect

    # 连接数据库

    conn = connect(host='localhost', port=3306, database='python_db', user='root', password='123123',charset='utf8')

    # 获取游标

    cur = conn.cursor()

    # 以字符串形式书写SQL语句

    # sql_str = '''insert into students values(0,'新来的',20,180,'男',1,1)'''

    # sql_str = '''update students set name = '王钢蛋' where name = '新来的'; '''

    sql_str = '''delete from students where name='王钢蛋'; '''

    # 执行SQL语句

    row_count = cur.execute(sql_str)

    # 在执行增删改操作时,需要向数据库提交操作,否则操作不成功

    conn.commit()

    # 关闭游标

    cur.close()

    # 关闭数据库

    conn.close()

      回滚(取消操作)

    # 导入模块

    from pymysql import connect

    # 连接数据库

    conn = connect(host='localhost', port=3306, database='python_db', user='root', password='123123',charset='utf8')

    # conn.autocommit(True)

    # 获取游标

    cur = conn.cursor()

    # 以字符串形式书写SQL语句

    sql_str = '''insert into students values(0,'新来的',20,180,'男',1,1)'''

    #插入10条数据

    for i in range(10):

        # 执行SQL语句

        row_count = cur.execute(sql_str)

    # 在执行增删改操作时,如果不想提交前面的修改操作,可以使用 rollback 回滚取消操作

    conn.rollback()

    # 关闭游标

    cur.close()

    # 关闭数据库

    conn.close()

    2.6.5 参数化列表防止SQL注入

      什么是SQL注入?

          是指在连接SQL语句时,用户传入了非法的数据,使SQL语句的意义发生变化,导至数据泄露

      产生原因:

          后台对用户提交的带有恶意的数据和 SQL 进行字符串方式的拼接,得到了脱离原意的 SQL 语句,从而影响了 SQL 语句的语义,最终产生数据泄露的现象。

      如何防止:

          SQL 语句的参数化, 将 SQL 语句的所有数据参数存在一个列表中传递给 execute 函数的第二个参数

      注意:

          sql语句中 -- 代表注释的意思

          此处不同于python的字符串格式化,必须全部使用%s占位

      # 导入模块

      from pymysql import connect

      find_name = input("请输姓名:")

      # 连接数据库

      conn = connect(host='localhost', port=3306, database='python_db', user='root', password='123123', charset='utf8')

      # 获得Cursor对象

      cur = conn.cursor()

      # # # 非安全的方式

      # # # 输入 "小明" or 1

      # sql = '''select * from students where name=%s''' % find_name

      # print("""sql===>%s<====""" % sql)

      # # 执行select语句,并返回受影响的行数:查询所有数据

      # count = cur.execute(sql)

      # 安全的方式

      # 构造参数列表

      params = [find_name]

      sql = '''select * from students where name=%s;'''

      print("""sql===>%s<====""" % sql)

      # 执行select语句,execute方法在内部实现了防SQL注入的功能,但具体如何实现并不清楚,隐藏了细节

      count = cur.execute(sql, params)

      # 注意:

      # 如果要是有多个参数,需要进行参数化

      # 那么params = [数值1, 数值2....],此时sql语句中有多个%s即可

      # 打印受影响的行数

      print(count)

      # 获取查询的结果

      result = cur.fetchall()

      # 打印查询的结果

      print(result)

      # 关闭Cursor对象

      cur.close()

      # 关闭Connection对象

      conn.close()

    2.6.6 数据库编程练习

      准备数据

          创建数据库

              ■ create database JDDB charset=utf8;

              ■ use JDDB

          导入数据

              ■  source JDDB.sql

      代码实现

          1>判断当前是否是主程序

    if __name__ == '__main__':

    main()

      2>实现主函数

    def main():

    # 创建 JD 类的对象

    jd = JD()

    # 运行 run 方法

    jd.run()

      3>实现 JD 类 因为所有的操作都要操作数据库,为了避免代码冗余,所以将连接和关闭操作设计到类中

      对象创建成功,数据库就连接成功,对象销毁时,数据库关闭

    class JD(object):

    """JD 类,提供商品查询服务"""

    # 将数据库连接操作放到初化方法中,对象创建时,自动连接数据库

    def __init__(self):

    # 连接数据库

    self.__conn = connect(host='localhost', port=3306, database='JDDB', user='root', password='123123', charset='utf8')

    # 获取游标

    self.__cur = self.__conn.cursor()

    # 将数据库关闭操作放到 __del__方法中,当对象销毁时,自动关闭数据库

    def __del__(self):

    # 关闭游标

    self.__cur.close()

    # 关闭数据库

    self.__conn.close()

      4>实现 run 方法 因为需要重复选择,所以要用死循环

    # run 方法,提供显示接口

    def run(self):

    while True:

        print("1查询所有商品信息")

        print("2查询所有商品在种类信息")

        print("3查询所有商品在品牌信息")

        print("4添加商品种类")

        print("5根据id查询商品信息")

        print("6根据id查询商品信息安全方式")

        selectID = input('请输入要执行的功能编号:')

        if selectID == '1':

            # 查询所有商品信息

            self.fetch_all_info()

        elif selectID == '2':

            # 查询种类信息

            self.fetch_cate()

        elif selectID == '3':

            # 查询品牌信息

            self.fetch_brand()

        elif selectID == '4':

            # 添加一个商品类型

            self.add_info()

        elif selectID == '5':

            # 通过ID 查找商品

            self.find_info()

        elif selectID == '6':

            # 通过ID 查找商品 防SQL注入

            self.find_info_safe()

        else:

            print('输入行号不正确!')

      5>实现一个显示方法,用来输出结果

    # 用来显示结果的方法,私有,对外不可见

    def __show_result(self, result):

    for t in result:

        print(t)

      6>实现查询所有商品方法

    # 查询所有商品信息

    def fetch_all_info(self):

    sql_str = ''' select * from goods;'''

    self.__cur.execute(sql_str)

    self.__show_result(self.__cur.fetchall())

      7>查询种类信息

    # 查询种类信息

    def fetch_cate(self):

    sql_str = ''' select * from goods_cates;'''

    self.__cur.execute(sql_str)

    self.__show_result(self.__cur.fetchall())

      8>查询品牌信息

    # 查询品牌信息

    def fetch_brand(self):

    sql_str = ''' select * from goods_brands;'''

    self.__cur.execute(sql_str)

    self.__show_result(self.__cur.fetchall())

      9>添加商品类型

    # 添加商品类型

    def add_info(self):

    new_type = input('请输入商品类型:')

    sql_str = ''' insert into goods_cates values(0,"%s");'''% new_type #注意,这里占位符要加引号

    self.__cur.execute(sql_str)

    self.__conn.commit() # 修改操作要手动提交

      10>根据id 查找商品

    # 根据id查找商品

    def find_info(self):

    id = input('请输入ID:')

    sql_str = ''' select * from goods where id=%s;'''%id

    self.__cur.execute(sql_str)

    self.__show_result(self.__cur.fetchall())

      11>根据id 查找商品,案例防注入

    # 根据id查找商品,案例防SQL注入

    def find_info_safe(self):

    id = input('请输入ID:')

    sql_str = ''' select * from goods where id=%s;'''

    self.__cur.execute(sql_str,(id,))

    self.__show_result(self.__cur.fetchall())

    相关文章

      网友评论

          本文标题:Python 高级 16 数据库Pymysql

          本文链接:https://www.haomeiwen.com/subject/gzstcqtx.html