Navicat工具、pymysql模块

一 IDE工具介绍(Navicat)

  生产环境仍是推荐使用mysql命令行,但为了方便咱们测试,可使用IDE工具,咱们使用Navicat工具,这个工具本质上就是一个socket客户端,可视化的链接mysql服务端的一个工具,而且他是图形界面版的。咱们使用它和直接使用命令行的区别就相似linux和windows系统操做起来的一个区别。python

       下载连接:https://pan.baidu.com/s/1bpo5mqjmysql

  Navicat的安装教程看这篇博客:https://www.cnblogs.com/clschao/articles/10022040.htmllinux

  

 
掌握:
#1. 测试+连接数据库
#2. 新建库
#3. 新建表,新增字段+类型+约束
#4. 设计表:外键
#5. 新建查询
#6. 备份库/表

#注意:
批量加注释:ctrl+?键
批量去注释:ctrl+shift+?键
 

 

二 pymysql模块

  咱们要学的pymysql就是用来在python程序中如何操做mysql,它和mysql自带的那个客户端还有navicat是同样的,本质上就是一个套接字客户端,只不过这个套接字客户端是在python程序中用的,既然是客户端套接字,应该怎么用,是否是要链接服务端,而且和服务端进行通讯啊,让咱们来学习一下pymysql这个模块sql

 

#安装
pip3 install pymysql

 

  一 连接、执行sql、关闭(游标)数据库

    

 
import pymysql
user=input('用户名: ').strip()
pwd=input('密码: ').strip()

#连接,指定ip地址和端口,本机上测试时ip地址能够写localhost或者本身的ip地址或者127.0.0.1,而后你操做数据库的时候的用户名,密码,要指定你操做的是哪一个数据库,指定库名,还要指定字符集。否则会出现乱码
conn=pymysql.connect(host='localhost',port=3306,user='root',password='123',database='student',charset='utf8') #指定编码为utf8的时候,注意没有-,别写utf-8,数据库为
#获得conn这个链接对象
#游标 cursor=conn.cursor() #这就想到于mysql自带的那个客户端的游标mysql> 在这后面输入指令,回车执行 #cursor=conn.cursor(cursor=pymysql.cursors.DictCursor) #获取字典数据类型表示的结果:{'sid': 1, 'gender': '男', 'class_id': 1, 'sname': '理解'} {'字段名':值} #而后给游标输入sql语句并执行sql语句execute sql='select * from userinfo where name="%s" and password="%s"' %(user,pwd) #注意%s须要加引号,执行这句sql的前提是医药有个userinfo表,里面有name和password两个字段,还有一些数据,本身添加数据昂 print(sql) res=cursor.execute(sql) #执行sql语句,返回sql查询成功的记录数目,是个数字,是受sql语句影响到的记录行数,其实除了受影响的记录的条数以外,这些记录的数据也都返回了给游标,这个就至关于咱们subprocess模块里面的管道PIPE,乘放着返回的数据
#all_data=cursor.fetchall() #获取返回的全部数据,注意凡是取数据,取过的数据就没有了,结果都是元祖格式的
#many_data=cursor.fetchmany(3) #一下取出3条数据,
#one_data=cursor.fetchone() #按照数据的顺序,一次只拿一个数据,下次再去就从第二个取了,由于第一个被取出去了,取一次就没有了,结果也都是元祖格式的

  fetchone:(1, '男', 1, '理解')
  fetchone:(2, '女', 1, '钢蛋')
  fetchall:((3, '男', 1, '张三'), (4, '男', 1, '张一'))windows

#上面fetch的结果都是元祖格式的,无法看出哪一个数据是对应的哪一个字段,这样是否是不太好看,想想,咱们能够经过python的哪种数据类型,能把字段和对应的数据表示出来最清晰,固然是字典{'字段名':值}
#咱们能够再建立游标的时候,在cursor里面加上一个参数:cursor=conn.cursor(cursor=pymysql.cursors.DictCursor)获取的结果就是字典格式的,fetchall或者fetchmany取出的结果是列表套字典的数据形式

上面咱们说,咱们的数据取一次是否是就没有了啊,实际上不是的,这个取数据的操做就像读取文件内容同样,每次read以后,光标就移动到了对应的位置,咱们能够经过seek来移动光标
一样,咱们能够移动游标的位置,继续取咱们前面的数据,经过cursor.scroll(数字,模式),第一个参数就是一个int类型的数字,表示日后移动的记录条数,第二个参数为移动的模式,有两个值:absolute:绝对移动,relative:相对移动
#绝对移动:它是相对于全部数据的起始位置开始日后面移动的
#相对移动:他是相对于游标的当前位置开始日后移动的

#绝对移动的演示
#print(cursor.fetchall())
#cursor.scroll(3,'absolute') #从初始位置日后移动三条,那么下次取出的数据为第四条数据
#print(cursor.fetchone())

#相对移动的演示
#print(cursor.fetchone())
#cursor.scroll(1,'relative') #经过上面取了一次数据,游标的位置在第二条的开头,我如今相对移动了1个记录,那么下次再取,取出的是第三条,我相对于上一条,往下移动了一条
#print(cursor.fetchone())
print(res) #一个数字 cursor.close() #关闭游标 conn.close() #关闭链接 if res: print('登陆成功') else: print('登陆失败')
 

 

  

 

 

  二 execute()之sql注入socket

    以前咱们进行用户名密码认证是先将用户名和密码保存到一个文件中,而后经过读文件里面的内容,来和客户端发送过来的用户名密码进行匹配,如今咱们学了数据库,咱们能够将这些用户数据保存到数据库中,而后经过数据库里面的数据来对客户端进行用户名和密码的认证。ide

    自行建立一个用户信息表userinfo,里面包含两个字段,username和password,而后里面写两条记录函数

    

    

 
#咱们来使用数据来进行一下用户名和密码的认证操做
import
pymysql conn = pymysql.connect( host='127.0.0.1', port=3306, user='root', password='666', database='crm', charset='utf8' ) cursor = conn.cursor(pymysql.cursors.DictCursor) uname = input('请输入用户名:') pword = input('请输入密码:') sql = "select * from userinfo where username='%s' and password='%s';"%(uname,pword) res = cursor.execute(sql) #res咱们说是获得的行数,若是这个行数不为零,说明用户输入的用户名和密码存在,若是为0说名存在,你想一想对不 print(res) #若是输入的用户名和密码错误,这个结果为0,若是正确,这个结果为1 if res: print('登录成功') else: print('用户名和密码错误!') #经过上面的验证方式,比咱们使用文件来保存用户名和密码信息的来进行验证操做要方便不少。
 

 

    

    可是咱们来看下面的操做,若是将在输入用户名的地方输入一个 chao'空格而后--空格而后加上任意的字符串,就可以登录成功,也就是只知道用户名的状况下,他就能登录成功的状况:

 
uname = input('请输入用户名:')
pword = input('请输入密码:')

sql = "select * from userinfo where username='%s' and password='%s';"%(uname,pword)
print(sql)
res = cursor.execute(sql) #res咱们说是获得的行数,若是这个行数不为零,说明用户输入的用户名和密码存在,若是为0说名存在,你想一想对不

print(res) #若是输入的用户名和密码错误,这个结果为0,若是正确,这个结果为1
if res:
    print('登录成功')
else:
    print('用户名和密码错误!')
#运行看结果:竟然登录成功
请输入用户名:chao' -- xxx
请输入密码:
select * from userinfo where username='chao' -- xxx' and password='';
1
登录成功

咱们来分析一下:
此时uname这个变量等于什么,等于chao' -- xxx,而后咱们来看咱们的sql语句被这个字符串替换以后是个什么样子:
select * from userinfo where username='chao' -- xxx' and password=''; 其中chao后面的这个',在进行字符串替换的时候,咱们输入的是chao',这个引号和前面的引号组成了一对,而后后面--在sql语句里面是注释的意思,也就是说--后面的sql语句被注释掉了。也就是说,拿到的sql语句是select * from userinfo where username='chao';而后就去本身的数据库里面去执行了,发现可以找到对应的记录,由于有用户名为chao的记录,而后他就登录成功了,可是其实他连密码都不知道,只知道个用户名。。。,他完美的跳过了你的认证环节。
 

 

    而后咱们再来看一个例子,直接连用户名和密码都不知道,可是依然可以登录成功的状况:

 
请输入用户名:xxx' or 1=1 -- xxxxxx
请输入密码:
select * from userinfo where username='xxx' or 1=1 -- xxxxxx' and password='';
3
登录成功

咱们只输入了一个xxx' 加or 加 1=1 加 -- 加任意字符串
看上面被执行的sql语句你就发现了,or 后面跟了一个永远为真的条件,那么即使是username对不上,可是or后面的条件是成立的,也可以登录成功。
 

    上面两个例子就是两个sql注入的问题,看完上面这两个例子,有没有感受后背发凉啊同志们,别急,咱们来解决一下这个问题,怎么解决呢?

      有些网站直接在你输入内容的时候,是否是就给你限定了,你不能输入一些特殊的符号,由于有些特殊符号能够改变sql的执行逻辑,其实不光是--,还有一些其余的符号也能改变sql语句的执行逻辑,这个方案咱们是在客户端给用户输入的地方进行限制,可是别人可不能够模拟你的客户端来发送请求,是能够的,他模拟一个客户端,不按照你的客户端的要求来,就发一些特殊字符,你的客户端是限制不了的。因此单纯的在客户端进行这个特殊字符的过滤是不能解决根本问题的,那怎么办?咱们服务端也须要进行验证,能够经过正则来将客户端发送过来的内容进行特殊字符的匹配,若是有这些特殊字符,咱们就让它登录失败。

    在服务端来解决sql注入的问题:不要本身来进行sql字符串的拼接了,pymysql能帮咱们拼接,他可以防止sql注入,因此之后咱们再写sql语句的时候按下面的方式写:

 
以前咱们的sql语句是这样写的:
sql = "select * from userinfo where username='%s' and password='%s';"%(uname,pword)

之后再写的时候,sql语句里面的%s左右的引号去掉,而且语句后面的%(uname,pword)这些内容也不要本身写了,按照下面的方式写
sql = "select * from userinfo where username=%s and password=%s;"
难道咱们不传值了吗,不是的,咱们经过下面的形式,在excute里面写参数:
#cursor.execute(sql,[uname,pword]) ,其实它本质也是帮你进行了字符串的替换,只不过它会将uname和pword里面的特殊字符给过滤掉。

看下面的例子:
uname = input('请输入用户名:') #输入的内容是:chao' -- xxx或者xxx' or 1=1 -- xxxxx
pword = input('请输入密码:')

sql = "select * from userinfo where username=%s and password=%s;"
print(sql)
res = cursor.execute(sql,[uname,pword]) #res咱们说是获得的行数,若是这个行数不为零,说明用户输入的用户名和密码存在,若是为0说名存在,你想一想对不

print(res) #若是输入的用户名和密码错误,这个结果为0,若是正确,这个结果为1
if res:
    print('登录成功')
else:
    print('用户名和密码错误!')
#看结果:
请输入用户名:xxx' or 1=1 -- xxxxx
请输入密码:
select * from userinfo where username=%s and password=%s;
0
用户名和密码错误!
 

 

  经过pymysql提供的excute完美的解决了问题。

总结我们刚才说的两种sql注入的语句
#
一、sql注入之:用户存在,绕过密码 chao' -- 任意字符 #二、sql注入之:用户不存在,绕过用户与密码 xxx' or 1=1 -- 任意字符

    解决方法总结:

 
# 原来是咱们对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的规矩来。
 
 

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

    查操做在上面已经说完了,咱们来看一下增删改,也要注意,sql语句不要本身拼接,交给excute来拼接


 
import pymysql
#连接
conn=pymysql.connect(host='localhost',port='3306',user='root',password='123',database='crm',charset='utf8')
#游标
cursor=conn.cursor()

#执行sql语句
#part1
# sql='insert into userinfo(name,password) values("root","123456");'
# res=cursor.execute(sql) #执行sql语句,返回sql影响成功的行数
# print(res)
# print(cursor.lastrowid) #返回的是你插入的这条记录是到了第几条了 #part2 # sql='insert into userinfo(name,password) values(%s,%s);' # res=cursor.execute(sql,("root","123456")) #执行sql语句,返回sql影响成功的行数 # print(res) #还能够进行更改操做:
#res=cursor.excute("update userinfo set username='taibaisb' where id=2")
#print(res) #结果为1 #part3 sql='insert into userinfo(name,password) values(%s,%s);' res=cursor.executemany(sql,[("root","123456"),("lhf","12356"),("eee","156")]) #执行sql语句,返回sql影响成功的行数,一次插多条记录 print(res) #上面的几步,虽然都有返回结果,也就是那个受影响的函数res,可是你去数据库里面一看,并无保存到数据库里面, conn.commit() #必须执行conn.commit,注意是conn,不是cursor,执行这句提交后才发现表中插入记录成功,没有这句,上面的这几步操做其实都没有成功保存。 cursor.close() conn.close()

  四 查:fetchone,fetchmany,fetchall

    

 
import pymysql
#连接
conn=pymysql.connect(host='localhost',user='root',password='123',database='egon')
#游标
cursor=conn.cursor()

#执行sql语句
sql='select * from userinfo;'
rows=cursor.execute(sql) #执行sql语句,返回sql影响成功的行数rows,将结果放入一个集合,等待被查询

# cursor.scroll(3,mode='absolute') # 相对绝对位置移动
# cursor.scroll(3,mode='relative') # 相对当前位置移动
res1=cursor.fetchone()
res2=cursor.fetchone()
res3=cursor.fetchone()
res4=cursor.fetchmany(2)
res5=cursor.fetchall()
print(res1)
print(res2)
print(res3)
print(res4)
print(res5)
print('%s rows in set (0.00 sec)' %rows)



conn.commit() #提交后才发现表中插入记录成功
cursor.close()
conn.close()

'''
(1, 'root', '123456')
(2, 'root', '123456')
(3, 'root', '123456')
((4, 'root', '123456'), (5, 'root', '123456'))
((6, 'root', '123456'), (7, 'lhf', '12356'), (8, 'eee', '156'))
rows in set (0.00 sec)
'''

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

 
import pymysql
conn=pymysql.connect(host='localhost',user='root',password='123',database='egon')
cursor=conn.cursor()

sql='insert into userinfo(name,password) values("xxx","123");'
rows=cursor.execute(sql)
print(cursor.lastrowid) #在插入语句后查看

conn.commit()

cursor.close()
conn.close()
 

 

回到顶部

相关文章
相关标签/搜索