python操作MySQL


:
python中支持操作MySQL的模块很多 其中最常见的当属'pymysql'
属于第三方模块

一.python操作MySQL

import pymysql
# 1.链接mysql服务端
ti_obj = pymysql.connect(
    host='127.0.0.1',             # MySQL服务端的ip地址
    port=3306,                    # MySQL默认的port地址(端口号)
    user='root',                  # 用户名
    passwd='*****',               # 密码
    database='qwq',               # 库名
    charset='utf8'                # 字符编码 类型
)
# 2.获取光标原来是元组格式转换为字典格式更佳精确
cursor = ti_obj.cursor(
    cursor=pymysql.cursors.DictCursor    # 获取光标 并转换为字典格式
)
# 3.编写sql语句
sql1 = 'select * from q1;'               # 获取q1表内数据
# 4.执行指定sql语句并执行SQL语句之后受影响的行数
affect_rows = cursor.execute(sql1)       # 行数 5行
# 5.获取结果
res = cursor.fetchall()
print(res)

补充获取结果控制光标移动获取指定结果以图为例子

fetchall():获取表内所有结果
fetchone():获取表内第一个数据
fetchmany(3):获取指定个数数据
cursor.scroll(1, 'relative')  # 相对于当前位置往后移动一个单位
cursor.scroll(1, 'absolute')  # 相对于起始位置往后移动一个单位

二.SQL注入

1.写正确的用户名错误的密码也可以登录
用户名:123456    密码0000   # 可以登陆
用户名:-- 123456 密码回车   # 可以登陆

'原因在sql语法中 --代表注释语法 '

2.用户名与密码都不需要也可以登陆
用户名:123456              密码0000   # 可以登陆
用户名:xxx or 1=1 --111    密码回车   # 可以登陆

'原因在sql语法中 ro 1=1 相当于逻辑运算True orTrue'

1.解决SQL注入方法

execute方法自带校验SQL注入问题 自动处理特殊符号
sql = "select * from 表名 where name=%s and pwd=%s;"
cursor.execute(sql, (name, pwd))   # 处理特殊符号

2.二次确认

使用python操作mysql数据库时
数据的增删改查四个操作是有轻重之分的
查 不会影响数据
增加,删除,修改 都会影响数据的本质
pymysql针对增、改、删三个操作 都设置了二次确认 如果不确认则不会真正影响数据库
方式1:代码直接编写
	affect_row = cursor.execute(sql)
	conn_obj.commit()    # 手动二次确认
方式2:配置固定参数
        conn_obj = pymysql.connect(
        autocommit=True       # 自动二次确认

三.修改表SQL语法补充

# 1.修改表的名字  rename
  alter table qqqq rename t1;
# 2.添加字段	add
  alter table ttt add pwd int;              '默认是尾部追加字段'

  alter table ttt add tid int after name;   '指定追加位置'

  alter table ttt add nid int first;        '指定头部添加字段'

# 3.修改字段change(名字类型都可)/modify(只能改类型不能改名字)
  alter table t1 change pwd password tinyint;

# 4.删除字段 drop
	alter table t1 drop nid;

四.视图

"""
视图的概念 
	通过SQL语句的执行得到的一张虚拟表 保存下来之后就称之为'视图'
视图的作用
	如果需要频繁的使用一张虚拟表 可以考虑制作成视图 降低操作难度
		两个表之间的拼接
视图的制作
	create view 视图名 as sql语句
"""
# 视图虽然看似很好用 但是会造成表的混乱 毕竟视图不是真正的数据源
# 视图只能用于数据的查询 不能做增、删、改的操作 可能会影响原始数据(视图里面的数据是直接来源于原始表 而不是拷贝一份)

五.触发器

触发器概念
在对表数据进行增、删、改的具体操作下,自动触发的功能
触发器作用
专门针对表数据的操作 定制个性化配套功能
触发器种类
表数据新增之前、新增之后
表数据修改之前、修改之后
表数据删除之前、删除之后

1.触发器创建

	create trigger 触发器名字 before/after insert/update/delete
	on 表名 for each row
		begin
			SQL语句
		end

触发器的名字一般情况下建议采用下列布局形式
		tri_after_insert_t1      # t1添加数据之后触发
		tri_before_update_t2     # t2更新之前触发
		tri_before_delete_t3     # t3删除之前触发 

2.具体案例

临时修改SQL语句的结束符 delimiter $$
临时修改的原因是因为触发器 存储过程等技术点 代码中也需要使用分号
如果不修改 则无法书写出完成的代码

1.先创建两张表
    CREATE TABLE t1 (
        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 t2 (
        id INT PRIMARY KEY auto_increment,
        err_cmd CHAR (64),
        err_time datetime
    );

2.编写触发器

 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.仅仅往t1表中插入数据

INSERT INTO t1 (
          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');

在t1表中添加数据的同时 t2表内也会通过触发器 添加数据的时间

六.事物

事务的概念
事务可以包含诸多SQL语句并且这些SQL语句
要么同时执行成功 要么同时执行失败 这是事务的原子性特点

1.事物的四大特性

A:原子性
一个事务是一个不可分割的整体 里面的操作要么都成立要么都不成立
C:一致性
事务必须使数据库从一个一致性状态变到另外一个一致性状态
I:隔离性
并发编程中 多个事务之间是相互隔离的 不会彼此干扰
D:持久性
事务一旦提交 产生的结果应该是永久的 不可逆的

2.创建表及录入数据

  	create table user(
      id int primary key auto_increment,
      name char(32),
      balance int
      );
    insert into user(name,balance)
      values
      ('jason',1000),
      ('kevin',1000),
      ('tank',1000);

3.开启一个事务的操作

start transaction;
    编写SQL语句(同属于一个事务)
    	update user set balance=900 where name='jason';
			update user set balance=1010 where name='kevin'; 
			update user set balance=1090 where name='tank';
    事务回滚(返回执行事务操作之前的数据库状态)
    	rollback;  # 执行完回滚之后 事务自动结束
    事务确认(执行完事务的主动操作之后 确认无误之后 需要执行确认命令)
    	commit;  # 执行完确认提交之后 无法回滚 事务自动结束

七.存储过程

可算是定义函数 调用函数

# 相当于定义函数
delimiter $$
create procedure p1()
begin
	select * from t1;
end $$
delimiter ;

# 相当于调用函数
call p1()

1.有参函数

 delimiter $$
  create procedure p1(
      in m int,  # in表示这个参数必须只能是传入不能被返回出去
      in n int,  
      out res int  # out表示这个参数可以被返回出去,还有一个inout表示即可以传入也可以被返回出去
  )
  begin
      select tname from userinfo where id > m and id < n;
      set res=0;  # 用来标志存储过程是否执行
  end $$
  delimiter ;

2.针对res需要先提前定义

set @res=10;  定义
  select @res;  查看
  call p1(1,5,@res)  调用
  select @res  查看

查看存储过程具体信息
	show create procedure pro1;
查看所有存储过程
	show procedure status;
删除存储过程
	drop procedure pro1;

八.函数

注意与存储过程的区别,mysql内置的函数只能在sql语句中使用

# 1.移除指定字符
Trim、LTrim、RTrim

# 2.大小写转换
Lower、Upper

# 3.获取左右起始指定个数字符
Left、Right

# 4.返回读音相似值(对英文效果)
Soundex

1.日期格式

'''在MySQL中表示时间格式尽量采用2022-11-11形式'''
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');

1.where Date(sub_time) = '2015-03-01'
2.where Year(sub_time)=2016 AND Month(sub_time)=07;
# 更多日期处理相关函数 
	adddate	增加一个日期 
	addtime	增加一个时间
	datediff	计算两个日期差值

九.流程控制

# python if判断
	if 条件:
    子代码
  elif 条件:
    子代码
  else:
    子代码
# js if判断
	if(条件){
    子代码
  }else if(条件){
    子代码
  }else{
    子代码
  }
# MySQL if判断
	if 条件 then
        子代码
  elseif 条件 then
        子代码
  else
        子代码
  end if;
  
# MySQL while循环
	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没有任何约束功能只会帮你加速查询
# ps:foreign key不是用来加速查询用的,不在我们研究范围之内

# 索引的基本用法
id	name	pwd		post_comment  addr  age 
	基于id查找数据很快 但是基于addr查找数据就很慢 
  	解决的措施可以是给addr添加索引
'''索引虽然好用 但是不能无限制的创建!!!'''
**索引的影响:**
	* 在表中有大量数据的前提下,创建索引速度会很慢
	* 在索引创建完毕后,对表的查询性能会大幅度提升,但是写的性能会降低

索引的底层数据结构是b+树
	b树 红黑树 二叉树 b*树 b+树
  	上述结构都是为了更好的基于树查找到相应的数据

只有叶子结点存放真实数据,根和树枝节点存的仅仅是虚拟数据
查询次数由树的层级决定,层级越低次数越少
一个磁盘块儿的大小是一定的,那也就意味着能存的数据量是一定的。如何保证树的层级最低呢?一个磁盘块儿存放占用空间比较小的数据项
思考我们应该给我们一张表里面的什么字段字段建立索引能够降低树的层级高度>>> 主键id字段

"""
聚集索引(primary key)
辅助索引(unique key,index key)
	查询数据的时候不可能都是用id作为筛选条件,也可能会用name,password等字段信息,那么这个时候就无法利用到聚集索引的加速查询效果。就需要给其他字段建立索引,这些索引就叫辅助索引

叶子结点存放的是辅助索引字段对应的那条记录的主键的值(比如:按照name字段创建索引,那么叶子节点存放的是:{name对应的值:name所在的那条记录的主键值})
数据查找 如果一开始使用的是辅助索引 那么还需要使用聚焦索引才可以获取到真实数据

覆盖索引:只在辅助索引的叶子节点中就已经找到了所有我们想要的数据
	select name from user where name='jason';
非覆盖索引:虽然查询的时候命中了索引字段name,但是要查的是age字段,所以还需要利用主键才去查找
	select age from user where name='jason';
"""
posted @ 2022-05-09 21:42  笑舞狂歌  阅读(2423)  评论(0编辑  收藏  举报