进击のpython
数据库——pymysql
数据库就算是学习完毕了,但是我们学习数据库的本质是什么?
是想让数据库像文件存储一样将信息存储起来供我们调用
那回归本行,我就应该是用python来处理数据库的相关操作
所以从这节开始就开始python跟数据库建立联系了
pymysql是一个第三方库,是用来使用Python语句来操作mysql的库
本质上就是个套接字连接
因为是第三方库,所以要安装~
我们用一个实例来带领你学习如何使用这个数据库
验证账号密码
验证之前得有一个数据库存放账号密码,所以先用上一节的可视化工具建立一个
创建完之后打开编译工具,调用pymysql:
import pymysql
因为他也相当于是套接字连接,所以首先应该建立联系,那都应该写什么呢?
pymysql.connect(
host='localhost', # ip
port=3306, # 端口
user='root', # 用户名
passwd='', # 密码
db='db10', # 连接的数据库
charset='utf8' # 编码方式
)
然后我们就要拿到游标,游标是什么呢?你注意到每次输入mysql语句的时候,都是 mysql>_
那这个_就是游标,我们输入SQL语句的手也是在这上面输入的,所以要先拿到游标:
cursor = conn.cursor()
我们是要验证账号密码,所以应该先输入再对比:
user = input('请输入用户名:').strip()
pwd = input('请输入密码:').strip()
sql='select * from user_info where name="%s" and pwd="%s"' %(user,pwd)
那执行给谁执行?游标!
rows = cursor.execute(sql)
这个拿到的结果是受影响的行数~也就是前几节命令执行完的最后一句话:3 rows in set (0.01 sec)
其实你想想,如果有行数改变,是不是就说明查找到了呢!
那执行完之后要把数据库关掉
cursor.close()
conn.close()
接下来就开始判断了:
if rows:
print('登陆成功!')
else:
print('登陆失败!')
完整代码:
import pymysql
user = input('请输入用户名:').strip()
pwd = input('请输入密码:').strip()
conn = pymysql.connect(
host='localhost', # ip
port=3306, # 端口
user='root', # 用户名
password='', # 密码
db='db10', # 连接的数据库
charset='utf8' # 编码方式
)
cursor = conn.cursor()
sql = 'select * from user_info where name="%s" and pwd="%s"' % (user, pwd)
rows = cursor.execute(sql)
cursor.close()
conn.close()
if rows:
print('登陆成功!')
else:
print('登陆失败!')
SQL注入
来,先不用管这个SQL注入是什么,我来让你看一个现象
其实刚才咱们的代码有致命的漏洞,不信你看
很明显,这也登陆成功了!为什么呢???
那我是不是把账号密码都输入到sql里面了,我现在打印一下,看看是什么:
select * from user_info where name="apple" -- dawdwa" and pwd=""
注意!!!在sql语句中,杠杠空格后面的语句就是注释掉了!
所以实际上你只执行到了这句话
select * from user_info where name="apple"
当然就成功登录了!
好!那又有疑问了!那我这么写的前提是我得知道用户名,不知道也是登不上去的啊,所以不算致命漏洞
那你看这个!
卧槽!也成功了!这是不是就瞬间慌了!
是不是实际上执行的是
select * from user_info where name="xxx " or 1=1
问题是不是就严重起来了????其实这种情况就是sql注入!!!!
如何解决呢??其实很好解决,只要不让它输入这种非法字符就行了!
其实你也就知道了为什么有的网站在创建用户名的时候不让用特殊符号了
那如何才能检测用户输入的特殊字符呢??
pymysql的模块作者想到了这一点,然后就给你提供了execute来过滤掉这些非法字符
所以部分代码应该这样修改:
sql = 'select * from user_info where name=%s and pwd=%s'
rows = cursor.execute(sql, (user, pwd))
pymysql的增删改查
增 删 改
之所以把这三个放在一起,本质上都是对库进行了修改,所以放在一起,讲一个就能举一反三
sql = 'insert into user_info(name,pwd) values (%s,%s)'
rows = cursor.execute(sql, ("orange", "147258"))
到这就出现问题了,实际上,这么写不会真的修改数据库,如果你真的想改,就要在
conn.close()前面加上conn.commit(),加个提交才可以!
执行完之后用可视化工具看一眼吧~
但是我这样只能添加一个,我想一次添加多个怎么办呢??
那就要用到executemany方法了,列表里包裹的一个元祖就是一组数据
rows = cursor.executemany(sql, [("pear", "147258"), ('peach', '789456')])
最后再用可视化工具看一下,看看添没添加成功
查
这两面来回很麻烦,有没有能让结果在编译器里打印的呢?
有!一共有三个方法:
cursor.fetchall() # 拿出所有
cursor.fetchone() # 拿到一条数据,相当于把结果放进管道一个一个拿出来
cursor.fetchmany() # 指定取多少条
但是我拿到的只有数据,要是能加上字段就好了~
所以!字典就变成首选,那如何能让返回的数据变成字典呢?
我们可以在设置游标的时候设置:
cursor = conn.cursor(pymysql.cursors.DictCursor)
这是啥意思啊,是不是基于字典的游标啊,这回你再查:
print(cursor.fetchone())
print(cursor.fetchone())
print(cursor.fetchone())
{'id': 1, 'name': 'apple', 'pwd': '123456'}
{'id': 2, 'name': 'banana', 'pwd': '654321'}
{'id': 3, 'name': 'orange', 'pwd': '147258'}
是不是就是带有字段的了~
print(cursor.fetchmany(3))
[{'id': 1, 'name': 'apple', 'pwd': '123456'}, {'id': 2, 'name': 'banana', 'pwd': '654321'}, {'id': 3, 'name': 'orange', 'pwd': '147258'}]
print(cursor.fetchall())
[{'id': 1, 'name': 'apple', 'pwd': '123456'}, {'id': 2, 'name': 'banana', 'pwd': '654321'}, {'id': 3, 'name': 'orange', 'pwd': '147258'}, {'id': 4, 'name': 'pear', 'pwd': '147258'}, {'id': 5, 'name': 'peach', 'pwd': '789456'}]
那有的同学发现我featchall()了之后,再featchall()就会返回一个空列表
那我不想这样,我就想每一次featchall,都是完整打印,怎么办呢?
其实这就有点像文件操作的时候通过光标的移动来决定打印内容
在数据库这里就是通过游标位置来决定打印内容,对于游标的移动有两种方式
绝对移动:cursor.scroll(3,mode='absolute')
相对移动:cursor.scroll(3,mode='relative')
绝对移动就是从头开始移动几个:
cursor.scroll(3,mode='absolute')
print(cursor.fetchone())
{'id': 4, 'name': 'pear', 'pwd': '147258'}
相对移动就是根据当前的游标位置进行移动
print(cursor.fetchone())
cursor.scroll(2, mode='relative')
print(cursor.fetchone())
{'id': 1, 'name': 'apple', 'pwd': '123456'}
{'id': 4, 'name': 'pear', 'pwd': '147258'}
最后说一点,pymysql提供了一种方法,能够让你知道现在id走到哪了,在插入数据的时候可以使用
sql = 'insert into user_info(name,pwd) values (%s,%s)'
rows = cursor.execute(sql,('plum',888888))
print(cursor.lastrowid)
代表着id要从6开始,也代表着,plum这个数据的id是6!