python第三方模块之pymysql

python第三方模块之pymysql

首先我们要先向解释器中安装pymysql模块:

pip install pymysql

与数据库建立连接

conn = pymysql.connect(
    host='127.0.0.1',  # 与本地数据库建立连接,可以尝试其他电脑的ip地址
    port=3306,  # 端口可写可不写,默认3306
    user='root',
    password="111",
	database="navicat_test1",  # 选择一个库,关键字可以简化为db
    charset="utf8mb4"
)  # 更多参数可以点进connect的源码去看

数据库模块的使用

  1. 产生游标对象

    # cursor = conn.cursor()  # 括号内不填写额外参数 数据是元组 指定性不强  [(),()]
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)  # [{},{}]
    
  2. 编写sql

    sql = "select * from class"  # 查找库navicat_test1下的表class
    
  3. 交由服务端执行

    affect_rows = cursor.execute(sql)  # 返回sql影响的数据行数
    print(affect_rows)
    
  4. 获取执行的结果

    cursor.fetchone()  # 从当前位置 拿到一条执行结果
    cursor.fetchall()  # 拿到所有结果
    crusor.fetchmany(n)  # 从当前位置 拿到多个结果
    

    游标的含义就是可以移动,我们在拿结果时,游标会自动的往后移动,如果我们想重新拿到前面的结果,可以使用滚动方法:

    cursor.scroll(1,'relative')  # 基于当前位置往后移动
    cursor.scroll(0,'absolute')  # 基于数据的开头往后移动
    

补充

在pymysql中,在查询时我们不需要二次确认,但是涉及增改删操作时,我们的mysql好像没有响应我们,这是因为mysql在触及这些操作时会问我们的客户端是否确认操作。

我们需要在执行完,对其进行确认

cursor.execute("update class set caption='五年5班' where cid=10")  # 改动某个数据值
conn.commit()  # 针对 增 删 改 需要二次确认(代码确认)

这样就可以通过python代码实现对数据库数据的增删改查了。

而二次确认其实也不用我们专门写一下,还可以在连接时添加一个配置参数就行:

conn = pymysql.connect(
    host='127.0.0.1', 
    port=3306, 
    user='root',
    password="111",
	database="navicat_test1",
    charset="utf8mb4",
    autocommit=True  # <---自动确认增删改
)

用数据库完成注册登录功能

import pymysql

conn = pymysql.connect(
    host='127.0.0.1',
    port=3306,
    user='root',
    password="111",
    database="a_pro_user",
    charset="utf8mb4",
    autocommit=True,  # <---自动确认增删改
)


def teacher_register():
    cursor = conn.cursor()
    while True:
        username = input('请输入用户名:').strip()
        sql = f"select name from a_pro_user.teacher where name='{username}';"
        cursor.execute(sql)  # 通过sql语句来判断库中是否有相关用户
        if cursor.fetchone():  # 如果拿到数据,说明有相关用户
            print('你输入的用户名已经被注册了')
            continue
        password = input('请输入密码:').strip()
        confirm_pwd = input('请确认密码:').strip()
        if not password == confirm_pwd:
            print('两次输入的密码不一致')
            continue
        sql = f"insert into a_pro_user.teacher(name, pwd) values ('{username}',password('{password}'));"
        cursor.execute(sql)   # 通过sql语句插入用户密码等数据
        print('注册成功')


def teacher_login():
    cursor = conn.cursor()
    while True:
        username = input('请输入用户名:').strip()
        password = input('请输入密码:').strip()
        sql = f"select name,pwd from a_pro_user.teacher where name='{username}'and pwd=password('{password}')"
        cursor.execute(sql)  # 用户密码对的上某一条数据,则能搜索搭到相关数据
        if cursor.fetchone():
            print('登录成功')
            break
        print('用户名或者密码输入错误!')

        
func_dict = {
    '1': teacher_register,
    '2': teacher_login,
}

def run():
    while True:
        choice = input('''
    1 老师注册
    2 老师登录
    输入功能编号:''').strip()
        if choice == 'q':
            quit()
        if choice in func_dict:
            func_dict.get(choice)()
        else:
            print('编号输入的不对')


if __name__ == '__main__':
    run()

sql注入问题

将上述代码的登录功能拿出来,用户输入时可以通过sql语法改写我们的sql句法结构。

cursor = conn.cursor()
username = input('请输入用户名:').strip()
password = input('请输入密码:').strip()
sql = f"select name,pwd from a_pro_user.teacher where name='{username}'and pwd=password('{password}')"
print(sql)  # 检查sql语句
cursor.execute(sql)  # 用户密码对的上某一条数据,则能搜索搭到相关数据
if cursor.fetchone():
    print('登录成功')
else:
    print('用户名或者密码输入错误!')

如以下的演示运行,我们可能出现以下的问题。

# ``中是用户输入数据
# 正常登录
> 请输入用户名:`leethon`
> 请输入密码:`123`
> select name,pwd from a_pro_user.teacher where name='leethon'and pwd=password('123')
> 登录成功
# 只知道用户名,也可以登录成功
> 请输入用户名:`leethon' -- sdfsdf`
> 请输入密码:
> select name,pwd from a_pro_user.teacher where name='leethon' -- sdfsdf'and pwd=password('')
> 登录成功
# 甚至不知道用户名,也可以登录成功
> 请输入用户名:sdjf' or True -- sdfsdf
> 请输入密码:
> select name,pwd from a_pro_user.teacher where name='sdjf' or True -- sdfsdf'and pwd=password('')
> 登录成功

发生上述情况,我们需要观察我们输入的数据以及最终拼接成的sql语句:

  • select name,pwd from a_pro_user.teacher where name='leethon' -- sdfsdf'and pwd=password('')

    这是知道用户名而跳过密码的登录成功所运行的sql语句,可以看见,在筛选过name='leethon'后就都是注释了,所以就跳过了对密码的验证。

  • select name,pwd from a_pro_user.teacher where name='sdjf' or True -- sdfsdf'and pwd=password('')

    这个就更狠了,在我们验证用户名的信息后又用逻辑运算or了一个bool值TRUE所以筛选条件where后面就相当于一直为真,表中的所有记录都会被查询。

这就是sql注入问题:利用特殊符合的组合产生特殊的含义,从而避开正常的业务逻辑

而针对sql问题的解决,解决方案其实pymysql也为我们提供了。

sql注入的解决

sql = " select * from a_pro_user.teacher where name=%s and pwd=%s "  # 用占位符来占位
cursor.execute(sql, (username, password(password))  # 直接在execute方法中用元组参数的方式传入占位字符。     
而关于py模块的sql语句,也可以一次多次重复执行,并一次传入多个参数,如我们要插入多条数据:
sql = "insert into a_table values(%s,%s,%s)"
executemany(sql,[(),(),(),()...])  #一次用列表元组执行,方法名是executemany()
posted @ 2022-11-28 19:09  leethon  阅读(2793)  评论(0编辑  收藏  举报