MySQL高级笔记——Pymysql
2019-01-29 02:12
375 查看
版权声明:欢迎转载~ 转载请注明来源及作者,谢谢! https://blog.csdn.net/qq_42442369/article/details/86684942
pymyql是Python中操作MySQL的模块,支持python3,用法和MySQLdb一样,不过后者不支持3.x版本。
pymysql版本:0.8.0
python版本:3.6.3
mysql版本:5.7.19
1. 安装
pip install pymysql
2. 使用操作
2.1 执行SQL
import pymysql """ python 连接数据库,任意数据库: 1、建立连接 2、获取操作的游标 3、调用对应的api函数,譬如 execute, 执行 SQL 语句 4、提交 commit 5、关闭游标 6、关闭连接 """ # 创建连接 conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='mysql1802', charset='utf8') # 创建游标 cursor = conn.cursor() # 执行SQL,并返回收影响行数 """ select 查询数据记录 """ # effect_row = cursor.execute("select * from emp") # print(effect_row) # l_1 = cursor.fetchone() # print(l_1) # l_all = cursor.fetchall() # print(l_all) """ 带参数的查询 fetchmany ,参数 size, 需要获取的记录数,超过总记录条数,不会报错,只是返回所有记录 """ # cursor.execute("select * from emp where deptno=%s", (30,)) # for emp in cursor.fetchmany(20): # print(emp) """ update """ # effect_row = cursor.execute("update emp set sal = sal + 100 where empno = %s", (7499,)) # print(effect_row) """ insert 插入一条和多条 SQL 语句: insert into emp(empno, ename, job, mgr, hiredate, sal, comm, deptno) values ('9996', 'test1', 'CLERK', '7782', '1988-05-03 00:00:00', '2466.34', '59.66', '10'), ('9997', 'test2', 'CLERK', '7782', '1988-02-03 00:00:00', '3466.34', '59.66', '10') 在python中: cursor.executemany("insert into emp(empno, ename, job, mgr, hiredate, sal, comm, deptno) values(%s,%s,%s,%s,%s,%s,%s,%s)", [('9996', 'test1', 'CLERK', '7782', '1988-05-03 00:00:00', '2466.34', '59.66', '10'), ('9997', 'test2', 'CLERK', '7782', '1988-02-03 00:00:00', '3466.34', '59.66', '10')]) """ # 执行 insert 一条记录 # effect_row = cursor.execute("insert into emp(empno, ename, job, mgr, hiredate, sal, comm, deptno) values(%s,%s,%s,%s,%s,%s,%s,%s)", # ('9992', 'test0', 'CLERK', '7782', '1988-01-03 00:00:00', '2266.34', '55.66', '10')) # print(effect_row) # insert 多条记录 # effect_row = cursor.executemany("insert into emp(empno, ename, job, mgr, hiredate, sal, comm, deptno) values(%s,%s,%s,%s,%s,%s,%s,%s)", # [('9996', 'test1', 'CLERK', '7782', '1988-05-03 00:00:00', '2466.34', '59.66', '10'), # ('9997', 'test2', 'CLERK', '7782', '1988-02-03 00:00:00', '3466.34', '59.66', '10')]) # print(effect_row) """ delete """ effect_row = cursor.execute("delete from emp where empno=%s",(9992,)) print(effect_row) effect_row = cursor.executemany("delete from emp where empno=%s", ((9996,), (9997,))) print(effect_row) # 提交,不然无法保存新建或者修改的数据 conn.commit() # 关闭游标, 一定是先关闭游标,再关闭 connection cursor.close() # 关闭连接 conn.close()
注意:存在中文的时候,连接需要添加charset=‘utf8’,否则中文显示乱码。
2.2 执行SQL
import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='mysql1802', charset='utf8') cursor = conn.cursor() cursor.execute("select * from t_student") # 获取剩余结果的第一行数据 row_1 = cursor.fetchone() print(row_1) # 获取剩余结果前n行数据 # row_2 = cursor.fetchmany(3) # 获取剩余结果所有数据 # row_3 = cursor.fetchall() conn.commit() cursor.close() conn.close()
2.3 获取新创建数据自增ID
可以获取到最新自增的ID,也就是最后插入的一条数据ID
""" 获取 insert 后的最新的自增id """ import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='mysql1802') cursor = conn.cursor() effect_row = cursor.execute("insert into t_student(stuNo, stuName) values(%s,%s)", ('1088', 'test0')) conn.commit() # 获取自增id new_id = cursor.lastrowid """ 如果 insert 的表,是以 id 作为主键进行update和delete的, 这个 lastrowid 对于 单条 数据的插入,具有很大意义 因为我们后续的对本条记录的操作都是 类似如下: delete from t_student where id = new_id的值 update t_student set 字段=新的值 where id = new_id的值 不是用 lastrowid,必须手动使用如下方式,但是此方式有可能 幻读 select id from t_student order by id desc limit 1 select max(id) from t_student 使用如下方式查找,通过刚刚insert的数据来获取对应的id 但是 insert 的记录有可能不唯一,取出多条记录来 获取多条记录中最大的,不是还是有 幻读 的可能 cursor.execute('select id from t_student where stuNo=%s and stuName=%s', ('1088', 'test0')) 要完全避免 幻读 ,必须设置 事务 的隔离级别为 最高 串行化 """ print(new_id) cursor.close() conn.close()
2.4 移动游标
操作都是靠游标,那对游标的控制也是必须的
注:在fetch数据时按照顺序进行,可以使用cursor.scroll(num,mode)来移动游标位置,如:
cursor.scroll(1,mode=‘relative’) # 相对当前位置移动
cursor.scroll(2,mode=‘absolute’) # 相对绝对位置移动
import pymysql """ 移动游标的位置 """ # 创建连接 conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='mysql1802', charset='utf8') # 创建游标 cursor = conn.cursor() effect_row = cursor.execute("select * from emp") print(cursor.fetchone()) # 相对移动,往后移动 1 步 cursor.scroll(-1, mode='relative') print(cursor.fetchone()) # 相对移动,往前移动 2 步 cursor.scroll(2, mode='relative') print(cursor.fetchone()) # 绝对移动,下标从 0 开始 cursor.scroll(0, mode='absolute') print(cursor.fetchone()) # 提交,不然无法保存新建或者修改的数据 conn.commit() # 关闭游标, 一定是先关闭游标,再关闭 connection cursor.close() # 关闭连接 conn.close()
2.5. fetch数据类型
关于默认获取的数据是元祖类型,如果想要或者字典类型的数据,即:
""" 默认返回的是 元组 可以修改为 dict 字典的 key 是字段名,所以 复杂的sql语句,需要使用 as 来重命名字段名 """ import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='mysql1802', charset='utf8') # 游标设置为字典类型 cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) cursor.execute("select * from emp") row_1 = cursor.fetchone() print(row_1) conn.commit() cursor.close() conn.close()
2.6 调用存储过程
a、调用无参存储过程
import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='mysql1802') # 游标设置为字典类型 cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) # 无参数存储过程 cursor.callproc('p2') # 等价于 # cursor.execute("call p2()") row_1 = cursor.fetchone() print(row_1) conn.commit() cursor.close() conn.close()
b、调用有参存储过程
"""" 调用带参数的存储过程 """ import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='mysql1802') # 游标设置为字典类型 cursor = conn.cursor() # 无参数存储过程 cursor.callproc('p1', args=(10,)) row_1 = cursor.fetchone() print(row_1) conn.commit() cursor.close() conn.close()
3 关于pymysql防注入
3.1 字符串拼接查询,造成注入
正常查询语句:
import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='mysql1802') cursor = conn.cursor() user="u1" passwd="u1pass" #正常构造语句的情况 sql="select user,pass from t_student where user='%s' and pass='%s'" % (user,passwd) #sql=select user,pass from t_student where user='u1' and pass='u1pass' row_count=cursor.execute(sql) row_1 = cursor.fetchone() print row_count,row_1 conn.commit() cursor.close() conn.close()
构造注入语句:
""" SQL 注入,正常用户的实现 create table puser( id int auto_increment primary key, username varchar(100), pwd varchar(100) ) insert into puser(username, pwd) values('admin', 'admin'); """ import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='mysql1802') cursor = conn.cursor() user = "admin" passwd = "admin" # 正常构造语句的情况 sql = "select username, pwd from puser where username='%s' and pwd='%s'" % (user, passwd) # 验证通过,该用户名和密码存在 row_count = cursor.execute(sql) row_1 = cursor.fetchone() print(row_count, row_1) conn.commit() cursor.close() conn.close()
3.2 避免注入,使用pymysql提供的参数化语句
正常参数化查询
""" 恶意构造SQL注入 通过这个示例告诉大家,一定不能拼接SQL 拼接后的SQL是: select username, pwd from puser where username='u1' or '1' -- ' and pwd='123456789' """ import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='mysql1802') cursor = conn.cursor() user = "u1' or '1'-- " passwd = "123456789" # 正常构造语句的情况 sql = "select username, pwd from puser where username='%s' and pwd='%s'" % (user, passwd) # 验证通过,该用户名和密码存在 row_count = cursor.execute(sql) row_1 = cursor.fetchone() print(row_count, row_1) conn.commit() cursor.close() conn.close()
构造注入,参数化查询注入失败
""" 通过这样的参数提交,不会被SQL注入 非法字符会被自动添加 \ 转义 select username, pwd from puser where username='u1\' or \'1\' -- ' and pwd='123456789' """ import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='mysql1802') cursor = conn.cursor() user = "u1' or '1'-- " passwd = "123456789" # 正常构造语句的情况 sql = "select username, pwd from puser where username='%s' and pwd='%s'" # 验证通过,该用户名和密码存在 row_count = cursor.execute(sql, args=(user, passwd)) row_1 = cursor.fetchone() print(row_count, row_1) conn.commit() cursor.close() conn.close()
结论:excute执行SQL语句的时候,必须使用参数化的方式,否则必然产生SQL注入漏洞。
4. 使用with简化连接过程
每次都连接关闭很麻烦,使用上下文管理,简化连接过程
import pymysql import contextlib """ 使用上下文管理器 """ # 定义上下文管理器,连接后自动关闭连接 @contextlib.contextmanager def mysql(host='127.0.0.1', port=3306, user='root', passwd='123456', db='mysql1802', charset='utf8'): conn = pymysql.connect(host=host, port=port, user=user, passwd=passwd, db=db, charset=charset) cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) try: yield cursor finally: conn.commit() cursor.close() conn.close() # 执行sql with mysql() as cursor: print(cursor) row_count = cursor.execute("select * from t_student") row_1 = cursor.fetchone() print(row_1)
项目:
1、实现 scrapyd 的其他几个接口
2、改造一个scrapy项目,将数据存储从 mongodb该到 mysql 数据库中
至少至少50%时间调试;
相关文章推荐
- Mysql DBA 高级运维学习笔记-生产场景Mysql主从复制读写分离授权方案及实战
- MySQL学习笔记_9_MySQL高级操作(上)
- Mysql DBA 高级运维学习笔记-DML语句之insert知识讲解
- Mysql DBA 高级运维学习笔记-初步增量恢复mysql数据库
- mysql 高级 笔记
- 高性能MYSQL(学习笔记)-MySQL高级特性3
- Mysql DBA 高级运维学习笔记-MySQL主从复制故障解决
- Mysql DBA 高级运维学习笔记-Mysql数据库字符集知识
- mysql高级笔记(二)
- 高性能MYSQL(学习笔记)-MySQL高级特性4
- Mysql DBA 高级运维学习笔记-一主多从宕机从库切换主库继续和从库同步过程
- Mysql DBA 高级运维学习笔记-Mysql数据库中的日志文件
- MySQL学习笔记_10_MySQL高级操作(下)
- Mysql DBA 高级运维学习笔记-Mysql双主及多主同步过程
- 关于mysql的sql语句的汇总(学习笔记)03(mysql高级应用)
- mysql笔记04 MySQL高级特性
- Mysql-学习笔记(==》连接查询_高级查询五)
- MySQL学习笔记_10_MySQL高级操作(下)
- 高性能MYSQL(学习笔记)-MySQL高级特性5
- MySQL学习笔记_10_MySQL高级操作(下)