MySQL数据库05
python操作MySQL
python中支持操作MySQL的模块很多,其中最常见的当属'pymysql'。属于第三方模块,pip3 install pymysql。
# 基本使用>>>:导入模块 import pymysql # 1.链接服务端 conn_obj = pymysql.connect( host='127.0.0.1', # MySQL服务端的IP地址 port=3306, # MySQL默认PORT地址(端口号) user='root', # 用户名 password='123', # 密码 也可以简写 passwd database='db1', # 库名称 也可以简写 db charset='utf8mb4' # 字符编码 千万不要加杠utf-8
autocommit=True # 执行增删改操作的时候,自动执行conn_obj.commit() ) # 要善于查看源码获取信息 # 2.产生获取命令的游标对象 cursor = conn_obj.cursor(cursor=pymysql.cursors.DictCursor) # 括号内不写参数 数据是元组,不够精确,添加参数则会将数据处理成字典 # 3.编写SQL语句 # sql1 = 'show tables;' sql1 = 'select * from teacher;' # SQL语句会被高亮显示 不用惊慌 # sql1 = 'select * from score;' # SQL语句会被高亮显示 不用惊慌 # 4.执行SQL语句 affect_rows = cursor.execute(sql1) # 发送给服务端 print(affect_rows) # 该方法的返回值res就是执行SQL语句之后表受影响的行数
# conn_obj.commit() # 修改数据库的操作需要二次确认
# 5.获取命令的执行结果 res = cursor.fetchall() # 获取所有的数据,结果是列表套字典 print(res)
''' 过程: 1. 建立连接 2. 设置一个可以执行sql语句的对象 - 游标 3. 通过该对象执行sql语句得到执行结果 4. 端口连接 '''
获取结果的注意事项: import pymysql # 1. 建立连接 conn = pymysql.connect(host="localhost", port=3306, db='db2', user='root', password='root') # 2. 设置游标 cursor = conn.cursor(pymysql.cursors.DictCursor) # 设置游标的具体类型, DictCursor拿到字段名 # 3. 执行sql语句 sql = 'select * from emp' res = cursor.execute(sql) # 结果的行数 print(res) # 需求: 具体的一条条记录 tag = cursor.fetchone() print(tag) print(tag['salary']) tag = cursor.fetchone() # 获取结果集当中的一条数据 print(tag) # cursor.scroll(1, mode='relative') # 指针相对于上一次位置往后偏移1条记录,基于数据集的当前位置 cursor.scroll(1, mode='absolute') # 指针绝对, 游标永远从头开始偏移,基于数据集开头的位置 tags = cursor.fetchall() # 获取结果集当中的所有的数据 print(tags)
tags1 = cursor.fetchall(100) # 获取结果集当中的指定条的数据,如果超出数据的最大条数,就显示所有条数据
print(tages1) cursor.close() conn.close()
pymysql处理sql注入问题
什么是sql注入:
通过书写sql包含(注释相关的)特殊符号,让原有的sql执行顺序发生改变,从而改变执行得到的sql。
本质:利用一些特殊符号的组合产生了特殊的含义,从而逃脱了正常的业务逻辑。
措施:针对用户输入的数据,不要自己处理,交给专门的方法自动过滤
没有处理sql注入的写法: sql = 'select * from user where usr="%s" and pwd="%s"' % (usr, pwd) res = cursor.execute(sql)
# sql注入 # 1.知道用户名: abc" -- hehe | ooo # select * from user where usr="abc" -- hehe" and pwd="ooo" # 2.不知道用户名 aaa" or 1=1 -- hehe | 000 # select * from user where usr="aaa" or 1=1 -- hehe" and pwd="000" # 处理sql注入: sql = 'select * from user where usr=%s and pwd=%s' res = cursor.execute(sql, (usr, pwd))
解决SQL注入的问题其实也很简单>>>:就是想办法过滤掉特殊符号!!!
execute方法自带校验SQL注入问题,能够自动处理特殊符号。
sql = "select * from userinfo where name=%s and password=%s;" cursor.execute(sql, (name, password))
''' sql语法中 注释: /**/ | -- | # 什么是sql注入: 通过书写sql包含(注释相关的)特殊字符, 让原有的sql执行顺序发生改变, 从而改变执行得到的sql 目的: 绕过原有的sql安全认证, 达到对数据库攻击的目的 ''' import pymysql conn = pymysql.connect(host='localhost', port=3306, user='root', passwd='root', db='db2') cursor = conn.cursor(pymysql.cursors.DictCursor) # 登录 # 得到用户输入的账户密码 usr = input("请输入用户名: ") #abc pwd = input("请输入密码: ") #123 # sql注入 # 1.知道用户名: abc" -- hehe | ooo # select * from user where usr="abc" -- hehe" and pwd="ooo" # 2.不知道用户名 aaa" or 1=1 -- hehe | 000 # select * from user where usr="aaa" or 1=1 -- hehe" and pwd="000" # 处理方式 # 对输入的账户密码做完全处理 => 不可能形成达到sql注入的特殊语法 => 正则 # 和数据库的账户密码进行配对 # sql = 'select * from user where usr="%s" and pwd="%s"' % (usr, pwd) # select * from user where usr="abc" and pwd="123" # res = cursor.execute(sql) # pymysql已经处理了sql注入 sql = 'select * from user where usr=%s and pwd=%s' res = cursor.execute(sql, (usr, pwd)) # print(res) if res: print('login success') else: print('login failed') cursor.close() conn.close()
pymysql二次确认>>>:增、删、改
pymysql针对增、改、删三个操作,都设置了二次确认,如果不确认,则不会真正影响数据库。
方式1:代码直接编写
# 手动二次确认 affect_row = cursor.execute(sql) conn_obj.commit()
方式2:配置固定参数
# 自动二次确认 conn_obj = pymysql.connect( autocommit=True )
增: 增加sql的语句: sql1 = 'insert into user(usr, pwd) values (%s, %s)' 在内存中一次插入一条: cursor.execute(sql1, ("opq", "123")) 在内存中插入多条 cursor.executemany(sql1, [("aaa", "000"), ("bbb", "111")]) 将内存中的数据提交到硬盘中: conn.commit() 删: sql2 = 'delete from user where usr=%s' cursor.execute(sql2, ("aaa")) conn.commit() 改: sql3 = 'update user set pwd=%s where usr=%s' res = cursor.execute(sql3, ("222", "bbb")) conn.commit()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | import pymysql conn = pymysql.connect(host = 'localhost' , port = 3306 , user = 'root' , passwd = 'root' , db = 'db2' ) cursor = conn.cursor(pymysql.cursors.DictCursor) # 增 # sql1 = 'insert into user(usr, pwd) values (%s, %s)' # cursor执行sql语句,在内存中完成了对数据的插入, 但不能将数据存放到硬盘 # 会将id完成自增 # 插入单条 # res = cursor.execute(sql1, ("opq", "123")) # 插入多条 #res = cursor.executemany(sql1, [("aaa", "000"), ("bbb", "111")]) # print(res) # 将内存中的数据提交给硬盘, 完成真实意义上的数据存储 # conn.commit() # 删 # sql2 = 'delete from user where usr=%s' # res = cursor.execute(sql2, ("aaa")) # print(res) # conn.commit() # 改 sql3 = 'update user set pwd=%s where usr=%s' res = cursor.execute(sql3, ( "222" , "bbb" )) conn.commit() cursor.close() conn.close() |
视图
- 什么是视图:
视图是由一张表或多张表的查询结果构成的一张虚拟表。
通过SQL语句的执行得到的一张虚拟表,保存下来之后就称之为'视图'。
- 为什么使用视图(视图的作用):
将复杂常用的查询结果保留下来重复使用(将一张大表拆分成多张小表)。
如果需要频繁的使用一张虚拟表,可以考虑制作成视图,降低操作难度。
- 视图相关语法:
视图的制作>>>:create view 视图名 as sql语句
create [or replace] view 视图名[(查询字段别名)] as 查询语句 create view new_emp as (select * from emp) 注: 1.查询字段别名们 要与 查询语句的查询字段对应 2.create or replace :操作视图,没有则创建,有则替换 create or replace view new_emp(id,姓名,工资) as (select id ,name,salary from emp where dep_id = 2); 视图的修改:alter 等价于 create or replace,且语法一致 alter view new_emp(id,姓名,工资) as (select id,name,salary from emp where dep_id = 1); 视图中字段的操作:不允许alter操作字段(下列操作是不被允许的) alter table new_emp reneme new_emp1; alter view new_emp modify id tinyint; 视图中记录的操作:等价于普通表,完成增删改查 update new_emp set 姓名='san' where id = 3; delete fro new_emp where id = 3; insert into new_emp(id, 姓名, 工资) values (10, "Bob", 10000); #操作的是实体表,虚拟表要重新创建才能拿到最新数据 视图的删除: drop view 视图名; 总结:虚拟表的作用——查询
ps:
视图只能用于数据的查询,不能做增、删、改的操作;视图里面的数据是直接来源于原始表,而不是拷贝一份!!!
触发器
- 什么是触发器:
在对表数据进行增、删、改的具体操作下,自动触发的功能。即:当表数据发生更新时,会自动触发的功能称之为触发器。
- 为什么使用触发器(触发器的作用):
当一个表在数据发生更新时,需要去完成一些操作,可以为具体数据更新的方式添加触发器。即:专门针对表数据的操作,定制个性化配套功能。
- 触发器种类:
- 表数据新增之前、新增之后
- 表数据修改之前、修改之后
- 表数据删除之前、删除之后
语法: delimiter // create trigger 触发器名 before | after insert | update | delete on 表名 for each row begin 需要触发执行的sql代码 end // delimiter; #触发器名:表名_(before|after)_(insert|update|delete)_trigger 注: delimiter 是用来修改sql的语句结束标识符 删除触发器:drop trigger 触发器名;
查看当前库下所有的触发器信息:show triggers\G;
eg:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | eg: 1. 创建两张表 CREATE TABLE cmd ( id INT PRIMARY KEY auto_increment, USER CHAR ( 32 ), priv CHAR ( 10 ), cmd CHAR ( 64 ), sub_time datetime, #提交时间 success enum ( 'yes' , 'no' ) #0代表执行失败 ); CREATE TABLE errlog ( id INT PRIMARY KEY auto_increment, err_cmd CHAR ( 64 ), err_time datetime ); 2. 需求:cmd表插入数据的success如果值为no 则去errlog表中插入一条记录 delimiter $$ # 将mysql默认的结束符由;换成$$ create trigger tri_after_insert_cmd after insert on cmd for each row begin if NEW.success = 'no' then # 新记录都会被MySQL封装成NEW对象 insert into errlog(err_cmd,err_time) values(NEW.cmd,NEW.sub_time); end if ; end $$ delimiter ; # 结束之后记得再改回来,不然后面结束符就都是$$了 3. 仅仅往cmd表中插入数据 INSERT INTO cmd ( USER, priv, cmd, sub_time, success )VALUES ( 'kevin' , '0755' , 'ls -l /etc' ,NOW(), 'yes' ), ( 'kevin' , '0755' , 'cat /etc/passwd' ,NOW(), 'no' ), ( 'kevin' , '0755' , 'useradd xxx' ,NOW(), 'no' ), ( 'kevin' , '0755' , 'ps aux' ,NOW(), 'yes' ); |
事务
- 事务是什么:
事务是逻辑上的一组操作,要么都成功,要么都失败。
事务可以包含诸多SQL语句,并且这些SQL语句要么同时执行成功,要么同时执行失败,这是事务的原子性特点。
- 为什么使用事务:
很多时候应该数据操作,不是一个sql语句就完成的,可能有很多个sql语句,如果部分sql执行成功而部分sql执行失败将导致数据错乱。
(例如:转账=>转入转出均成功,才能认为操作成功)
- 事务的四大特性:(ACID)
A:原子性>>>:事务是一组不可分割的单位,里面的操作要么都成立要么都不成立。
C:一致性>>>:事务必须使数据库从一个一致性状态变到另外一个一致性状态。即:事务前后的数据完整性应该保持一致。
I:隔离性>>>:事务的隔离性是指多个用户并发访问数据时,一个用户的事务不能被其他用户的事务所干扰,多个并发事务之间数据要相互隔离。
D:持久性>>>:持久性是指一个事务一旦被提交,它对数据的改变就是永久性的,不可逆的,接下来几十数据库发生故障也不应该对其有影响。
- 事务操作
开启一个事务的操作:
start transaction ;——开启事务,在这条语句之后的sql将处在同一事务,并不会立即修改数据库。
事务回滚:
返回执行事务操作之前的数据库状态。
rollback ;——回滚事务,取消这个事务,这个事务不会对数据库中的数据产生任何影响。执行完回滚之后,事务自动结束。
事务确认:
commit ;——提交事务,让这个事务中的sql立即执行事务的操作。(执行完事务的主动操作之后,确认无误之后,需要执行确认命令)。
- 事务的用户隔离级别
数据库使用者可以控制数据库工作在哪个级别下,就可防止不同的隔离性问题。
''' read uncommitted ——不做任何隔离,可能脏读,幻读 read committed ——可以防止脏读,不能防止不可重复读合幻读 Repeatable read ——可以防止脏读,不可重复读,不能防止幻读 Serializable——数据库运行在串行化实现,所有问题都没有,就是性能低 '''
- 修改隔离级别
''' select @@tx_isolation; ——查询当前级别 set[session|global] transaction isolation level ....;修改级别 '''
eg:set global transaction isolation level Repeatable read;
ps:修改后重新连接服务器生效。
存储过程
- 存储过程是什么:
用于完成指定功能的sql语句块,类似于Python中的自定义函数。
- 存储过程的优点:
将能指定功能的sql语句块建立成存储过程,不仅将sql语句逻辑化了,更是功能化了,那我们要完成相同的事,只需要重复使用建立的存储过程,不需要再重复书写sql语句了。
即>>>:存储过程可以让sql语句更具有复用性,从而提高开发效率。
''' 语法: delimiter $$ create procedure 存储过程名( 输入输出类型1 参数名1 参数类型1(宽度), ... , 输入输出类型n 参数名n 参数类型n(宽度) ) begin sql语句块 end $$ delimiter ; 注:1.输入输出类型:in | out | inout 2.call存储过程名(实参们)来调用存储过程
调用函数:call p1() '''
查看存储过程具体信息:show create procedure pro1;
查看所有存储过程:show procedure status;
删除存储过程:drop procedure pro1;
MySQL的内置函数
不同于存储过程,mysql内置的函数只能在sql语句中使用!!!
- 移除指定字符:Trim、LTrim、RTrim
- 大小写转换:Lower、Upper
- 获取左右起始指定个数字符:Left、Right
- 返回读音相似值(对英文效果):Soundex
- 日期格式:date_format
CREATE TABLE blog ( id INT PRIMARY KEY auto_increment, NAME CHAR (32), sub_time datetime ); INSERT INTO blog (NAME, sub_time) VALUES ('第1篇','2015-03-01 11:31:21'), ('第2篇','2015-03-11 16:31:21'), ('第3篇','2016-07-01 10:21:31'), ('第4篇','2016-07-22 09:23:21'), ('第5篇','2016-07-23 10:11:11'), ('第6篇','2016-07-25 11:21:31'), ('第7篇','2017-03-01 15:33:21'), ('第8篇','2017-03-01 17:32:21'), ('第9篇','2017-03-01 18:31:21'); select date_format(sub_time,'%Y-%m'),count(id) from blog group by date_format(sub_time,'%Y-%m');
ps:其他的日期处理相关函数
- adddate 增加一个日期
- addtime 增加一个时间
- datediff 计算两个日期差值
流程控制
- if语句的使用
第一种 if: """ if 条件 then 子语句; end if; """ 第二种 if elseif """ if 条件 then 子语句1; elseif 条件 then 子语句2; else 语句3; end if; """
- while循环
循环输出10次hello mysql create procedure showHello() begin declare i int default 0; while i < 10 do select "hello mysql"; set i = i + 1; end while; end
DECLARE num INT ; SET num = 0 ; WHILE num < 10 DO SELECT num ; SET num = num + 1 ; END WHILE ;
索引
索引就是一种数据结构,类似于书的目录。意味着以后再查数据应该先找目录再找数据,而不是用翻页的方式查询数据。
索引在MySQL中也叫做“键”,是存储引擎用于快速找到记录的一种数据结构。
primary key 主键
unique key 唯一键
index key 索引键
上面三种key前两种除了有加速查询的效果之外,还有额外的约束条件(primary key:非空且唯一,unique key:唯一);而index key没有任何约束功能只会帮你加速查询。
索引的基本用法:
id name pwd post_comment addr age
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?