zoukankan      html  css  js  c++  java
  • mysql五:pymysql模块

    一、介绍

      之前都是通过MySQ自带的命令行客户端工具Mysql来操作数据库,那如何在Python程序中操作数据库呢?这就需要用到pymysql模块了。

      这个模块本质就是一个套接字客户端软件,使用前需要实现安装

    pip3 install pymysql

    二、链接、执行sql、关闭游标

      通过Navicat创建一个db9数据库并创建userinfo表

    mysql> desc userinfo;
    +-------+----------+------+-----+---------+----------------+
    | Field | Type     | Null | Key | Default | Extra          |
    +-------+----------+------+-----+---------+----------------+
    | id    | int(11)  | NO   | PRI | NULL    | auto_increment |
    | user  | char(16) | NO   |     | NULL    |                |
    | pwd   | char(20) | YES  |     | NULL    |                |
    +-------+----------+------+-----+---------+----------------+
    
    mysql> select * from userinfo;
    +----+------+------+
    | id | user | pwd  |
    +----+------+------+
    |  1 | egon | 123  |
    |  2 | alex | 456  |
    +----+------+------+
    """
    """
    # 登录数据库,允许远程访问
    mysql> grant all on *.* to 'root'@'%' identified by '1234'; 
    Query OK, 0 rows affected, 1 warning (0.01 sec)
    
    # 立即刷新数据库,配置立即生效
    mysql> flush privileges;
    Query OK, 0 rows affected (0.01 sec)
    创建库表并授权

      mysql模块的基本使用:

    # -*- coding:utf-8 -*-
    __author__ = 'Qiushi Huang'
    
    import pymysql   # 套接字
    
    user = input('user>>:').strip()
    pwd = input('pwd>>:').strip()
    
    # 建立链接
    conn = pymysql.connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        password='1234',
        db='db9',
        charset='utf8'    # mysql指定utf-8的格式是没有杠的
    )
    
    # 拿到游标
    course=conn.cursor()     # 执行完毕返回的结果集默认以元组显示
    
    # 执行sql语句
    sql = 'select * from userinfo where user = "%s" and pwd="%s"' % (user, pwd)
    rows = course.execute(sql)   # 游标的execute接口传入sql语句,返回sql查询成功的记录数
    
    # 资源回收
    course.close()  # 关闭游标
    conn.close()    # 关闭连接
    
    # 进行判断
    if rows:
        print('登录成功')
    else:
        print('登录失败')
    """
    user>>:egon
    pwd>>:123
    登录成功
    """

    三、execute()之sql注入

      注意:符号--会注释掉它之后的sql,正确的语法:--后至少有一个任意字符

    # -*- coding:utf-8 -*-
    __author__ = 'Qiushi Huang'
    
    # pip3 install pymysql
    import pymysql   # 套接字
    
    user = input('user>>:').strip()
    pwd = input('pwd>>:').strip()
    
    # 建立链接
    conn = pymysql.connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        password='1234',
        db='db9',
        charset='utf8'    # mysql指定utf-8的格式是没有杠的
    )
    
    # 拿到游标
    course=conn.cursor()     # 执行完毕返回的结果集默认以元组显示
    
    # 执行sql语句
    sql = 'select * from userinfo where user = "%s" and pwd="%s"' % (user, pwd)
    print(sql)   # 查看被注入的sql
    rows = course.execute(sql)   # 游标的execute接口传入sql语句,返回sql查询成功的记录数
    
    # 资源回收
    course.close()  # 关闭游标
    conn.close()    # 关闭连接
    
    # 进行判断
    if rows:
        print('登录成功')
    else:
        print('登录失败')
    """
    user>>:egon" -- xxxx   # 双"-"之后全都变为注释
    pwd>>:123
    select * from userinfo where user = "egon" -- xxxx" and pwd="123"
    登录成功
    """
    
    # 不用输入密码直接登录,"和sql语句中的"拼接 , 或判断与1=1
    # user>>:xxx" or 1=1 -- hahahwdda" and pwd=""
    # pwd>>:
    # select * from userinfo where user = "xxx" or 1=1 -- hahahwdda and pwd=""" and pwd=""
    # 登录成功
    sql注入案例

      根本原理:就根据程序的字符串拼接name='%s',我们输入一个xxx' -- haha,用我们输入的xxx加'在程序中拼接成一个判断条件name='xxx' -- haha'

      解决办法:

    # 原来是我们对sql进行字符串拼接
    # sql="select * from userinfo where name='%s' and password='%s'" %(user,pwd)
    # print(sql)
    # res=cursor.execute(sql)
    
    #改写为(execute帮我们做字符串拼接,我们无需且一定不能再为%s加引号了)
    sql="select * from userinfo where name=%s and password=%s" #!!!注意%s需要去掉引号,因为pymysql会自动为我们加上
    res=cursor.execute(sql,[user,pwd]) #pymysql模块自动帮我们解决sql注入的问题,只要我们按照pymysql的规矩来。
    # -*- coding:utf-8 -*-
    __author__ = 'Qiushi Huang'
    
    # pip3 install pymysql
    import pymysql   # 套接字
    
    user = input('user>>:').strip()
    pwd = input('pwd>>:').strip()
    
    # 建立链接
    conn = pymysql.connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        password='1234',
        db='db9',
        charset='utf8'    # mysql指定utf-8的格式是没有杠的
    )
    
    # 拿到游标
    course=conn.cursor()     # 执行完毕返回的结果集默认以元组显示
    
    # 执行sql语句
    # sql = 'select * from userinfo where user = "%s" and pwd="%s"' % (user, pwd)
    # print(sql)   # 查看被注入的sql
    
    sql = 'select * from userinfo where user = %s and pwd=%s'
    rows = course.execute(sql, (user, pwd))   # 不使用字符串拼接,采用execute在后面传值的方式
    
    # 资源回收
    course.close()  # 关闭游标
    conn.close()    # 关闭连接
    
    # 进行判断
    if rows:
        print('登录成功')
    else:
        print('登录失败')
    """
    user>>:xxx" or 1=1 -- hahahwdda" and pwd=""
    pwd>>:
    登录失败
    """
    代码改造为防止sql注入

    四、增、删、改:conn.commit()

       增、删、改的操作相似。以对表格添加记录为例。

    # -*- coding:utf-8 -*-
    __author__ = 'Qiushi Huang'
    
    import pymysql
    
    # 建立链接
    conn = pymysql.connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        password='1234',
        db='db9',
        charset='utf8'    # mysql指定utf-8的格式是没有杠的
    )
    
    # 拿游标
    cursor=conn.cursor()
    
    # 执行sql
    # 增删改
    sql='insert into userinfo(user,pwd) values(%s,%s);'
    # 单一操作
    # res=cursor.execute(sql,("wxx","123")) #执行sql语句,返回sql影响成功的行数
    # print(res)
    
    # 批量操作
    cursor.executemany(sql,[('yxx','123'), ('egon1','123'), ('zurong','123')])
    
    
    conn.commit()   # 注意:提交后记录才会插入成功
    # 关闭链接
    cursor.close()
    conn.close()
    """
    +----+--------+------+
    | id | user   | pwd  |
    +----+--------+------+
    |  1 | egon   | 123  |
    |  2 | alex   | 456  |
    |  3 | hqs    | 123  |
    |  5 | wxx    | 123  |
    |  8 | yxx    | 123  |
    |  9 | egon1  | 123  |
    | 10 | zurong | 123  |
    +----+--------+------+
    """

    五、查:fetchone,fetchmany,fetchall

    # 建立链接
    conn = pymysql.connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        password='1234',
        db='db9',
        charset='utf8'    # mysql指定utf-8的格式是没有杠的
    )
    
    # 拿游标
    cursor=conn.cursor()
    
    # 执行sql查询
    rows = cursor.execute('select * from userinfo;')    # 把sql发给服务端
    # print(rows)   # 显示的仅仅是受影响的行数
    
    # 为了得到执行结果,需要使用fetchone()函数,一次得到一条服务端执行记录
    print(cursor.fetchone())
    print(cursor.fetchone())
    """
    (1, 'egon', '123')
    (2, 'alex', '456')
    """
    
    conn.commit()   # 注意:提交后记录才会插入成功
    # 关闭链接
    cursor.close()
    conn.close()
    查看记录

      可以看到上面的记录没有字段信息,很难分辨数据具体属于哪个字段。因此需要在拿游标时,使用:cursor=conn.cursor(pymysql.cursors.DictCursor)  得到基于字典的游标。

    conn = pymysql.connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        password='1234',
        db='db9',
        charset='utf8'    # mysql指定utf-8的格式是没有杠的
    )
    
    # 拿游标
    cursor=conn.cursor(pymysql.cursors.DictCursor)   # 基于字典的游标
    
    # 执行sql查询
    rows = cursor.execute('select * from userinfo;')
    # print(cursor.fetchone())
    # print(cursor.fetchone())
    """
    {'id': 1, 'user': 'egon', 'pwd': '123'}
    {'id': 2, 'user': 'alex', 'pwd': '456'}
    """
    
    # 一次取多个
    print(cursor.fetchmany(3))
    """
    [{'id': 1, 'user': 'egon', 'pwd': '123'}, {'id': 2, 'user': 'alex', 'pwd': '456'}, {'id': 3, 'user': 'hqs', 'pwd': '123'}]
    """
    
    # 全部取出
    print(cursor.fetchall())  # 如果是和上面的和语句一起执行,则是取出id=3之后的数据
    print(cursor.fetchall())  # 上一条取完所有数据,游标已经到了记录结尾,此次为空
    """
    [{'id': 1, 'user': 'egon', 'pwd': '123'}, {'id': 2, 'user': 'alex', 'pwd': '456'}, {'id': 3, 'user': 'hqs', 'pwd': '123'}]
    [{'id': 5, 'user': 'wxx', 'pwd': '123'}, {'id': 8, 'user': 'yxx', 'pwd': '123'}, {'id': 9, 'user': 'egon1', 'pwd': '123'}, {'id': 10, 'user': 'zurong', 'pwd': '123'}]
    []
    """
    
    conn.commit()   # 注意:提交后记录才会插入成功
    # 关闭链接
    cursor.close()
    conn.close()

      从上例中可以学习到fetchone,fetchmany,fetchall这三种方法的使用和区别。但是由此也看到,读取记录存在游标位置问题。

      相对绝对位置移动:cursor.scroll(3,mode='absolute')

      相对当前位置移动:cursor.scroll(3,mode='relative')

    conn = pymysql.connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        password='1234',
        db='db9',
        charset='utf8'    # mysql指定utf-8的格式是没有杠的
    )
    
    # 拿游标
    cursor=conn.cursor(pymysql.cursors.DictCursor)   # 基于字典的游标
    
    # 执行sql查询
    rows = cursor.execute('select * from userinfo;')
    print(cursor.fetchall())   # 先移动到最后
    # 游标移动——相对绝对位置移动
    cursor.scroll(2,mode='absolute') # 相对绝对位置移动——从结果最开始起到第2条数据结尾
    print(cursor.fetchone())
    print(cursor.fetchone())
    """
    [{'id': 1, 'user': 'egon', 'pwd': '123'}, ...]
    {'id': 3, 'user': 'hqs', 'pwd': '123'}
    {'id': 5, 'user': 'wxx', 'pwd': '123'}
    """
    
    # 游标移动——相对当前位置移动
    cursor.scroll(2,mode='relative') # 相对当前位置移动——从id=5这个结果开始,移动到id=9最后
    print(cursor.fetchone())
    print(cursor.fetchone())
    """
    {'id': 10, 'user': 'zurong', 'pwd': '123'}
    None    # 没有数据了还查询,即返回None
    """
    
    conn.commit()   # 注意:提交后记录才会插入成功
    # 关闭链接
    cursor.close()
    conn.close()
    """
    +----+--------+------+
    | id | user   | pwd  |
    +----+--------+------+
    |  1 | egon   | 123  |
    |  2 | alex   | 456  |
    |  3 | hqs    | 123  |
    |  5 | wxx    | 123  |
    |  8 | yxx    | 123  |
    |  9 | egon1  | 123  |
    | 10 | zurong | 123  |
    +----+--------+------+
    """

    六、获取插入的最后一条数据的自增ID

    # -*- coding:utf-8 -*-
    __author__ = 'Qiushi Huang'
    
    
    import pymysql
    # conn=pymysql.connect(host='127.0.0.1',user='root',password='1234',database='egon')
    conn = pymysql.connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        password='1234',
        db='db9',
        charset='utf8'    # mysql指定utf-8的格式是没有杠的
    )
    
    cursor=conn.cursor()
    
    sql='insert into userinfo(user,pwd) values("xxx","123");'
    rows=cursor.execute(sql)
    print(cursor.lastrowid)   # 插入之前id走到的数字(下一条即将插入的记录的id)
    
    conn.commit()
    
    cursor.close()
    conn.close()
    """
    11
    +----+--------+------+
    | id | user   | pwd  |
    +----+--------+------+
    |  1 | egon   | 123  |
    |  2 | alex   | 456  |
    |  3 | hqs    | 123  |
    |  5 | wxx    | 123  |
    |  8 | yxx    | 123  |
    |  9 | egon1  | 123  |
    | 10 | zurong | 123  |
    +----+--------+------+
    """
  • 相关阅读:
    MySQL Case When 用法
    Delphi磁性窗口
    一个灵巧的Delphi多播实事件现方案.
    Delphi bpl 插件框架
    Win7下超级管理员创建普通权限任务
    Delphi 插件(Plugins)创建、调试与使用应用程序扩展
    Dll中导出类Delphi实战
    让你的程序支持插件
    构造一个通用的回调Thunk.(把回调函数指向对象的方法的办法)
    打造类.NET带垃圾回收功能的Delphi版GDIPlus
  • 原文地址:https://www.cnblogs.com/xiugeng/p/9043758.html
Copyright © 2011-2022 走看看