zoukankan      html  css  js  c++  java
  • pymysql模块

    pymysql模块

    1.pymysql安装

    这是一个第三方的模块,需要提前安装

    使用清华源安装:(可以解决下载慢,超时导致下载失败等问题)

    pip3 install -i http://pypi.douban.com/simple/ pymysql
    

    2.基本使用流程

    先创建一个表用来当作实验表

    create database db666 charset='utf8';
    use db666;
    create table user(
    	id int primary key auto_increment,
        username varchar(24),
        password varchar(16)
    );
    insert into user(username,password) values('jkey',123),('tufei',222),('song',123),('dd',222),('jj',123),('kk',222),('uu',123),('yy',222),('nn',123),('cc',222);
    

    在pycharm中 使用pymysql

    # 1. 链接数据库 和 dos终端一样
    conn = pymysql.connect(
    	host='localhost',
        port=3306,
        user='root',
        password='jzd123',
        database='db666',
        'charset'='utf8'  # 注意是utf8不是utf-8
        
        # passwd='' 也可以指定密码
        # db='' 也可以指定数据库名 都是为了兼容mysqldb
    )
    
    # 2. 通过链接对象conn产生一个游标对象, 游标对象就相当于dos界面的执行行,等待输入指令的.  mysql>
    cursor = conn.cursor()
    
    # 3. 定义sql语句交给游标对象去执行
    """
    affected_rows = cursor.execute(sql)
    execute是给我们提交sql语句到数据库的,返回的是当前sql语句影响的行数,可以当作判断是否查找成功的依据
    """
    # 例如: 判断用户输入的账号和密码是否和数据库中存的一致
    username = input('请输入账号>>:').strip()
    password = input("请输入密码>>:").strip()
    
    sql = 'select * from user where username="%s" and password="%s"' % (username,password)  # 注意:%s要加上引号,是一个varchar类型
    affected_rows = cursor.execute(sql)
    print("影响了%s行"%affected_rows)
    
    if affected_rows:
        print("登录成功")
    else:
        print("用户名或者密码错误")
    

    3. 利用execute解决sql注入问题

    根本原理:利用一些SQL语法的特性, 书写一些特定的语句实现固定的语法. 这里就是利用的是MySQL的注释语法。 当然还有很多种,这里只是简单的一种列举。

    举例说明:

    Copy"""
    web端登陆时, 在应用程序级别, 先筛选一下特殊符号或者根本不让你输入特殊符号, 从服务器下载页面代码到客户端. 客户端的web端js代码把你有一些能改变sql语句逻辑的符号, and ,or, –- 注释等全部给你过滤掉, 再往服务端发, 再拼成sql语句, 往数据库上一提交, 但是这种安全是在前端界面实现的我们可以破解.
    
    破解: 过模拟浏览器的行为, 相当于跳过了你前端的js过滤监测, mysql服务端就嗝屁了
    """
    

    2种sql注入介绍:

    Copy# 1、sql注入之:用户存在,绕过密码
    jkey" #任意字符  或者  jkey"  -- 任意字符  (注意: 使用--这种注释语法后面必须跟一个空格, 后面才是任意字符. #号注释没有要求)
    
    # 2、sql注入之:用户不存在,绕过用户与密码
    xxx" or 1=1 #任意字符   或者   xxx" or 1=1 -- 任意字符  
    

    sql注入俩种解决方案

    import pymysql
    
    conn = pymysql.connect(host="localhost",user='root',password='jzd123',database='db666',charset='utf8')
    
    # curr = conn.cursor(cursor=pymysql.cursors.DictCursor)  # 将返回的查询结果变为列表套 key:values的形式
    curr = conn.cursor()  # 默认的sql语句的执行结果为大元组套小元组的形式
    
    inp_user = input('username>>>:').strip()
    inp_pwd = input('password>>>:').strip()
    
    # 解决sql注入问题方法1
    sql = rf'select * from user where username="{inp_user}" and password="{inp_pwd}"'  # 这样用自己的拼接方式会出现sql注入的问题,
    # # 例如:输入时输入 xxx" or 1=1 -- xx 就会破坏掉sql语句的本身意思,这时候你要想让sql语句的语句不被破坏,就得自己编写正则去匹配输入中是否有特殊符合,
    # # 有就处理这些特殊符合
    rows = curr.execute(sql)
    # 解决sql注入问题方法2
    # 将sql语句放到execute方法中,这个方法会帮我们处理这个问题
    # rows = curr.execute("select * from user where username=%s and password=%s", args=(inp_user, inp_pwd))
    
    print(rows)
    
    # res = curr.fetchall()
    #
    # print(res)
    if rows:
        print('登录成功')
    else:
        print('登录失败')
    
    curr.close()
    conn.close()
    

    4.fetch系列的方法

    该系列的方法是在pymysql中拿到sql语句执行的返回结果的

    例如.还是拿上面的user表演示

    import pymysql
    
    conn = pymysql.connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        passwd='jzd123',
        db='db666',
        charset='utf8'
    )
    
    # 注意: 游标对象默认拿到的返回数据是元组的类型,可以设置成字典的类型
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    
    while True:
        sql = input("mysql> ").strip()  # 输入 select * from user;
        print("sql:", sql)
        affected_rows = cursor.execute(sql)
        print('affected_rows:', affected_rows)
    
        # cursor.fetchone() 方法: 表示一次只拿一条数据,有值返回数据本身是字典类型,没有查询结果或者被取空都返回None
        """
        需要主要的是fetch系列的方法返回是迭代器,提交了一次只有一次的返回结果,取干净了就得重新提交sql语句了
        """
        print(cursor.fetchone())
        print(cursor.fetchone())
        """返回结果:
        {'id': 1, 'username': 'jkey', 'password': '123'}
    	{'id': 2, 'username': 'tufei', 'password': '222'}
    	"""
    
        # cursor.fetchmany(n) 可以一次取多条数据,有值就返回数据,列表套字典的类型,没有查询结果或者被取空都返回[]
        print(cursor.fetchmany(2))
        print(cursor.fetchmany(3))
        """返回结果
        [{'id': 3, 'username': 'song', 'password': '123'}, {'id': 4, 'username': 'dd', 'password': '222'}]
    	[{'id': 5, 'username': 'jj', 'password': '123'}, {'id': 6, 'username': 'kk', 'password': '222'}, {'id': 7, 'username': 'uu', 'password': '123'}]
        """
    
        # 3. cursor.fetchall(): 将所有的数据全部取空,有值就返回数据,列表套字典的类型,没有查询结果或者被取空都返回[]
        print(cursor.fetchall())
        print(cursor.fetchall())
        """返回结果
        [{'id': 8, 'username': 'yy', 'password': '222'}, {'id': 9, 'username': 'nn', 'password': '123'}, {'id': 10, 'username': 'cc', 'password': '222'}]
        []
        """
    

    5.指针的移动介绍(scroll)

    是搭配fetch系列的方法使用

    例如:

    import pymysql
    
    conn = pymysql.connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        passwd='jzd123',
        db='db666',
        charset='utf8'
    )
    
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    
    cursor.execute('select * from user;')
    
    """ 方法介绍
    cursor.scroll(x,relative/absolute)
    第一个参数为指针往后移动的位数
    第二个参数为选择相对移动还是绝对移动,默认为relative相对移动
    """
    # 1. relative 相对移动: 意思是相对于光标当前所在的位置继续往后移动x位
    cursor.scroll(1)  # 等价于 cursor.scroll(1,relative)
    print(cursor.fetchone())  # 注意: 读取数据类似于文件指针的移动
    cursor.scroll(3)
    print(cursor.fetchmany(2))
    """执行返回结果
    {'id': 2, 'username': 'tufei', 'password': '222'}
    [{'id': 6, 'username': 'kk', 'password': '222'}, {'id': 7, 'username': 'uu', 'password': '123'}]
    """
    
    # 2. 绝对移动: 相对于数据的开头位置往后继续移动1位
    cursor.scroll(1, 'absolute')
    print(cursor.fetchone())
    cursor.scroll(3, 'absolute')
    print(cursor.fetchmany(2))
    """执行后返回结果
    {'id': 2, 'username': 'tufei', 'password': '222'}
    [{'id': 4, 'username': 'dd', 'password': '222'}, {'id': 5, 'username': 'jj', 'password': '123'}]
    """
    

    6.增删改介绍(execute系列)

    在python中针对数据库的提交,都是execute帮我们提交的sql语句,如果是查的话,是可以直接拿取到数据的,而如果是增删改的话,考虑到数据的安全性,我们需要二次确认之后才能真正的操作硬盘上的数据

    commit方法

    import pymysql
    
    conn = pymysql.connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        passwd='jzd123',
        db='db666',
        charset='utf8',
        # autocommit=True  # 默认是Flase,设为True之后,对于增删改的操作就不需要二次提交了 即 下面的conn.commit() 就可以不用写了
    )
    
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    
    # 修改之前查看一下数据
    cursor.execute('select * from user;')
    print(cursor.fetchall())
    
    # 往数据库 user 表 里面增数据
    # 1. cursor.execute()  表示指定单个sql语句
    sql = 'insert into user(username,password) values("刘大傻","dsb")'
    cursor.execute(sql)
    """
    在dos界面查看 是否插入成功
    mysql> select * from user;
    +----+----------+----------+
    | id | username | password |
    +----+----------+----------+
    |  1 | jkey     | 123      |
    |  2 | tufei    | 222      |
    |  3 | song     | 123      |
    |  4 | dd       | 222      |
    |  5 | jj       | 123      |
    |  6 | kk       | 222      |
    |  7 | uu       | 123      |
    |  8 | yy       | 222      |
    |  9 | nn       | 123      |
    | 10 | cc       | 222      |
    +----+----------+----------+
    10 rows in set (0.00 sec)
    发现并没有插入到数据库中,这也证实了需要二次确认的观念
    """
    cursor.execute('select * from user;')
    print(cursor.fetchall())  # 但是自己这个客户端是可以查看到的昂 {'id': 13, 'username': '刘大傻', 'password': 'dsb'}
    
    # 2.cursor.execute(): 指定单个sql语句+过滤特殊符号和敏感关键字
    sql = 'insert into user(username,password) values(%s,%s)'
    cursor.execute(sql, ("拍打星", "123"))
    cursor.execute(sql, ["拍打星2", "123"])
    cursor.execute(sql, args=["拍打星3", "123"])  # 元组,列表的形式都可以
    
    # 3.cursor.executemany()  可以一次提交多个sql语句+ 过滤特殊符号和敏感关键字
    sql = "insert into  user(username,password) values(%s,%s)"
    cursor.executemany(sql, [("蛋蛋", "123"), ("可可", '234'), ("大大", "234")])
    
    # 删
    sql = 'delete from user where id<10'
    cursor.execute(sql)
    
    # 改
    sql = 'update user set username="杨二傻" where id=10'
    cursor.execute(sql)
    
    # 补充:  execute之for循环实现executemany的功能
    user_info = [
        ('jj', '123'),
        ('dd', '323'),
        ('aa', '444')
    ]
    for user in user_info:
        sql = "insert into user(username, password) values (%s, %s);"
        cursor.execute(sql, user)
    
    # 提交
    conn.commit()  # 注意: 增删改操作必须指定commit才会生效
    
    """修改后查"""
    cursor.execute('select * from user;')
    print(cursor.fetchall())
    
    cursor.close()
    conn.close()
    """最后提交后的结果
    mysql> select * from user;
    +----+------------+----------+
    | id | username   | password |
    +----+------------+----------+
    | 10 | cc         | 222      |
    | 38 | 刘大傻     | dsb      |
    | 39 | 拍打星     | 123      |
    | 40 | 拍打星2    | 123      |
    | 41 | 拍打星3    | 123      |
    | 42 | 蛋蛋       | 123      |
    | 43 | 可可       | 234      |
    | 44 | 大大       | 234      |
    | 45 | jj         | 123      |
    | 46 | dd         | 323      |
    | 47 | aa         | 444      |
    +----+------------+----------+
    """
    

    7. 获取插入的最后一条数据的自增ID

    Copyimport pymysql
    
    conn = pymysql.connect(
        host='localhost',
        user='root',
        password='jzd123',
        database='db666'
    )
    cursor = conn.cursor()
    
    sql = 'insert into user(username,password) values("xxxx","123");'
    rows = cursor.execute(sql)
    print(cursor.lastrowid)  # 在插入语句后查看. 获取插入的最后一条数据的自增ID, 如果插入数据之前id是10, 执行execute以后返回的值是11. 返回结果是int类型.
    
    conn.commit()
    
    cursor.close()
    conn.close()
    
  • 相关阅读:
    ByteBuffer的slice()方法
    Kafka多个消费者的小例子
    设计模式之迭代器模式
    设计模式之责任链模式
    @ComponentScan的scopeResolver属性详解
    ES中的文档更新
    ElasticSearch学习:安装
    强、软、弱、虚四大引用示例
    20个有用的小片段
    spring mvc 执行流程
  • 原文地址:https://www.cnblogs.com/jkeykey/p/14457442.html
Copyright © 2011-2022 走看看