第11天,Python操作MySQL

@(python)[笔记]

目录

一、数据库操作
    1.1 数据库管理
        1.1.1 显示
        1.1.2 用户管理
        1.1.3 授权管理
    1.2 数据表操作
        1.2.1 创建表
            数据类型
            修饰符
        1.2.2 删除表
        1.2.3 清空表
        1.2.4 修改表
    1.3 表内容操作
        1.3.1 增
        1.3.2 删
        1.3.3 改
        1.3.4 查
        1.3.5 复杂查询
二、Python操作MySQL
    2.1 下载安装
    2.2 使用操作
        2.2.1 执行查询操作
        2.2.2 写库操作必须提交commit
        2.2.3 直接获取新增数据的自增ID
        2.2.4 将查询结果以字典形式返回

一、数据库操作

SQL语句分类:

SQL语句分为:
(1) DQL(数据查询语言):select
(2) DDL(数据定义语言):create/drop/alter/truncate
(3) DML(数据操纵语言):insert/update/delete
 (4)  TCL(事务控制语言):commit/rollback/savepoint
(5) DCL(数据控制语言):grant/revoke

1.1 数据库管理

1.1.1 显示

SHOW DATABASES //显示所有数据库
SHOW TABLES //显示所有数据表
USE db_name //使用某个数据库

默认的数据库功能介绍

  • mysql - 用户权限相关数据
  • test - 用于用户测试数据
  • information_schema - MySQL本身架构相关数据

1.1.2 用户管理

创建用户
    create user '用户名'@'IP地址' identified by '密码';
    
删除用户
    drop user '用户名'@'IP地址';
    
修改用户
    rename user '用户名'@'IP地址'; to '新用户名'@'IP地址';;
    
修改密码
    set password for '用户名'@'IP地址' = Password('新密码')
  
PS:用户权限相关数据保存在mysql数据库的user表中,所以也可以直接对其进行操作(不建议)

1.1.3 授权管理

show grants for '用户'@'IP地址';            -- 查看权限
grant  权限 on 数据库.表 to   '用户'@'IP地址';      -- 授权
revoke 权限 on 数据库.表 from '用户'@'IP地址';      -- 取消权限

权限列表

权限名称 权限功能
all privileges 除grant外的所有权限
select 仅查权限
select,insert 查和插入权限
usage 无访问权限
alter 使用alter table
alter routine 使用alter procedure和drop procedure
create 使用create table
create routine 使用create procedure
create temporary tables 使用create temporary tables
create user 使用create user、drop user、rename user和revoke all privileges
create view 使用create view
delete 使用delete
drop 使用drop table
execute 使用call和存储过程
file 使用select into outfile 和 load data infile
grant option 使用grant 和 revoke
index 使用index
insert 使用insert
lock tables 使用lock table
process 使用show full processlist
select 使用select
show databases 使用show databases
show view 使用show view
update 使用update
reload 使用flush
shutdown 使用mysqladmin shutdown(关闭MySQL)
super <dbff><dc42><dbff><dc08>使用change master、kill、logs、purge、master和set global。还>允许mysqladmin<dbff><dd57><dbff><dd58><dbff><dc8a><dbff><dc8b>调试登陆
replication client 服务器位置的访问
replication slave 由复制从属使用

对于数据库

对于目标数据库以及内部其他:

数据库表示 说明
数据库名.* 数据库中的所有
数据库名.表 指定数据库中的某张表
数据库名.存储过程 指定数据库中的存储过程
*.* 所有数据库

对于用户和IP地址

表示方法 说明
用户名@IP地址 用户只能在改IP下才能访问
用户名@192.168.1.% 用户只能在改IP段下才能访问(通配符%表示任意)
用户名@% 用户可以再任意IP下访问(默认IP地址为%)

刷新权限列表

flush privileges //将数据读取到内存中,从而立即生效

root忘记密码解决办法

# 启动免授权服务端
mysqld --skip-grant-tables

# 客户端
mysql -u root -p

# 修改用户名密码
update mysql.user set authentication_string=password('666') where user='root';

#刷新权限列表
flush privileges;

1.2 数据表操作

1.2.1 创建表

参考博客1

参考博客2

create table 表名(
    列名  类型  是否可以为空,
    列名  类型  是否可以为空
)ENGINE=InnoDB DEFAULT CHARSET=utf8
数据类型

1. 数值类型

数值类型 字节 范围(有符号) 范围(无符号) 用途
TINYINT 整数 1字节 (-128,127) (0,255) 小整数值
SMALLINT 整数 2字节 (-32 768,32 767) (0,65 535) 大整数值
MEDIUMINT 整数 3字节 (-8 388 608,8 388 607) (0,16 777 215) 大整数值
INT或INTEGER 整数 4字节 (-2 147 483 648,2 147 483 647) (0,4 294 967 295) 大整数值
BIGINT 整数 8字节 (-9 233 372 036 854 775 808,9 223 372 036 854 775 807) (0,18 446 744 073 709 551 615) 极大整数值
FLOAT 浮点数 4字节 (-3.402 823 466 E+38,1.175 494 351 E-38) (0,3.402 823 466 351 E+38) 单精度浮点数值
DOUBLE 浮点数 8字节 (1.797 693 134 862 315 7 E+308,2.225 073 858 507 201 4 E-308) 0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) 双精度浮点数值
DECIMAL 浮点数 未知 未知 未知 绝对精度

2. 字符串类型

字符串类型 字节大小 描述及存储需求
CHAR 0-255字节 定长字符串
VARCHAR 0-255字节 变长字符串
TINYBLOB 0-255字节 不超过 255 个字符的二进制字符串
TINYTEXT 0-255字节 短文本字符串
BLOB 0-65535字节 二进制形式的长文本数据
TEXT 0-65535字节 长文本数据
MEDIUMBLOB 0-16 777 215字节 二进制形式的中等长度文本数据
MEDIUMTEXT 0-16 777 215字节 中等长度文本数据
LOGNGBLOB 0-4 294 967 295字节 二进制形式的极大文本数据
LONGTEXT 0-4 294 967 295字节 极大文本数据
VARBINARY(M) 允许长度0-M个字节的定长字节符串,值的长度+1个字节
BINARY(M) 允许长度0-M个字节的定长字节符串

3. 日期和时间类型

类型 大小(字节) 范围 格式 用途
DATE 4 1000-01-01/9999-12-31 YYYY-MM-DD 日期值
TIME 3 '-838:59:59'/'838:59:59' HH:MM:SS 时间值或持续时间
YEAR 1 1901/2155 YYYY 年份值
DATETIME 8 1000-01-01 00:00:00/9999-12-31 23:59:59 YYYY-MM-DD HH:MM:SS 混合日期和时间值
TIMESTAMP 4 1970-01-01 00:00:00/2037 年某时 YYYYMMDD HHMMSS 混合日期和时间值,时间戳

4. ENUM枚举类型

ENUM 类型因为只允许在集合中取得一个值,有点类似于单选项。在处理相互排拆的数据时容易让人理解,比如人类的性别。ENUM 类型字段可以从集合中取得一个值或使用 null 值。

5. SET 集合类型

SET 类型与 ENUM 类型相似但不相同。SET 类型可以从预定义的集合中取得任意数量的值。并且与 ENUM 类型相同的是任何试图在 SET 类型字段中插入非预定义的值都会使
MySQL 插入一个空字符串。如果插入一个即有合法的元素又有非法的元素的记录,MySQL 将会保留合法的元素,除去非法的元素。

修饰符
  • NOT NULL / NULL 表示是否可为空
  • **DEFAULT Null ** 表示默认值为Null
  • auto_increment ** 表示自增,注意:**1.每个表只允许有一列为自增列;2. 对于自增列,必须是索引(含主键);3. 对于自增,可以设置步长和起始值。
  • primary key 表示设为主键,注意:主键,是一种特殊的唯一索引,不允许有空值,如果主键使用单个列,则它的值必须唯一,如果是多列,则其组合必须是唯一。
  • 设置外键constraint fk_name foreign key 字段名 references 外表名(字段名),加粗字体为关键字,fk_name为自定义的外键名。
  • UNSIGNED 修饰符规定字段只保存正值。

1.2.2 删除表

drop table 表名

1.2.3 清空表

delete from 表名       //不会清空自增ID
truncate table 表名    //会将自增ID也清空

1.2.4 修改表

添加列:alter table 表名 add 列名 类型
删除列:alter table 表名 drop column 列名
修改列:
        alter table 表名 modify column 列名 类型;  -- 类型
        alter table 表名 change 原列名 新列名 类型; -- 列名,类型
  
添加主键:
        alter table 表名 add primary key(列名);
删除主键:
        alter table 表名 drop primary key;
        alter table 表名  modify  列名 int, drop primary key;
  
添加外键:alter table 从表 add constraint 外键名称(形如:FK_从表_主表) foreign key 从表(外键字段) references 主表(主键字段);
删除外键:alter table 表名 drop foreign key 外键名称
  
修改默认值:ALTER TABLE testalter_tbl ALTER i SET DEFAULT 1000;
删除默认值:ALTER TABLE testalter_tbl ALTER i DROP DEFAULT;

1.3 表内容操作

1.3.1

insert into 表 (列名,列名...) values (值,值,值...)
insert into 表 (列名,列名...) values (值,值,值...),(值,值,值...)   //一次插入多行
insert into 表 (列名,列名...) select (列名,列名...) from 表    //插入的值是从其它表查询到的结果

1.3.2

delete from 表     //清空表内容
delete from 表 where id=1 and name='alex'     //根据指定条件删除对应的行

1.3.3

update 表 set name = 'alex' where id>1

1.3.4

查询语法:
   SELECT *|field1,filed2 ...   FROM tab_name
                  WHERE 条件
                  GROUP BY field
                  HAVING 筛选
                  ORDER BY field
                  LIMIT 限制条数
Mysql在执行sql语句时的执行顺序:
            -- from  where  select  group by  having order by
select * from 表
select * from 表 where id > 1
select nid,name,gender as gg from 表 where id > 1
select distinct gender from student;  //distinct 可以让相同的值只出现一次

1.3.5 复杂查询

a、条件

    select * from 表 where id > 1 and name != 'alex' and num = 12;
 
    select * from 表 where id between 5 and 16;
 
    select * from 表 where id in (11,22,33)
    select * from 表 where id not in (11,22,33)
    select * from 表 where id in (select nid from 表)

b、通配符

    select * from 表 where name like 'ale%'  - ale开头的所有(多个字符串)
    select * from 表 where name like 'ale_'  - ale开头的所有(一个字符)

c、限制

    select * from 表 limit 5;            - 前5行
    select * from 表 limit 4,5;          - 从第4行开始的5行
    select * from 表 limit 5 offset 4    - 从第4行开始的5行

注意:NULL作比较时,不能使用=等于号,要用 is

d、排序


    select * from 表 order by 列 asc              - 根据 “列” 从小到大排列
    select * from 表 order by 列 desc             - 根据 “列” 从大到小排列
    select * from 表 order by 列1 desc,列2 asc    - 根据 “列1” 从大到小排列,如果相同则按列2从小到大排序
 

e、分组

    select num from 表 group by num
    
    select num,nid from 表 group by num,nid
    
    select num,nid from 表  where nid > 10 group by num,nid order nid desc
    
    select num,nid,count(*),sum(score),max(score),min(score) from 表 group by num,nid
 
    select num from 表 group by num having max(id) > 10

计算男生和女生的平均年龄:
select avg(age) from student group by gender;
    

注意:特别的:group by 必须在where之后,order by之前。having 后跟过滤条件,只能跟group by 一起用,用于将group by分组后的结果再次过滤;分组的主要目的就是做聚合计算的。

  • sum() 求和
  • min() 求最小值
  • max() 求最大值
  • avg() 求平均值
  • count() 求次数
  • count()* 统计符合条件的记录条数

聚合函数的括号中填一个列名,例如:sum(number)表示计算number这一列数值的和。

f、连表

    无对应关系则不显示
    select A.num, A.name, B.name
    from A,B
    Where A.nid = B.nid
 
    无对应关系则不显示
    select A.num, A.name, B.name
    from A inner join B
    on A.nid = B.nid
 
    A表所有显示,如果B中无对应关系,则值为null
    select A.num, A.name, B.name
    from A left join B
    on A.nid = B.nid
 
    B表所有显示,如果B中无对应关系,则值为null
    select A.num, A.name, B.name
    from A right join B
    on A.nid = B.nid

g、组合

    组合,自动处理重合
    select nickname
    from A
    union
    select name
    from B
 
    组合,不处理重合
    select nickname
    from A
    union all
    select name
    from B

h、正则表达式过滤

REGEXP或者RLIKE  
    支持正则表达式过滤
    select * from 表 where name like '^ale'    //查找name是以ale开头的行

二、Python操作MySQL

在Python中操作MySQL用pymysql模块,其使用方法和MySQLdb几乎相同。

2.1 下载安装

pip3 install pymysql

2.2 使用操作

2.2.1 执行查询操作

import pymysql

# 创建连接
conn = pymysql.Connect(host="127.0.0.1",
                       port=3306,
                       user="root",
                       password="123456",
                       database="study",
                       charset="utf8")
# 创建游标,利用游标支数据库取数据
cursor = conn.cursor()

#执行SQL,返回值v是受影响的行数
v = cursor.execute('select * from student')
result = cursor.fetchall()   #获取返回的全部数据,元组形式
# result = cursor.fetchone()   #获取返回的第1条数据
# result = cursor.fetchmany(2)   #获取返回的指定行数的数据,不指定行数,默认只获取一行数据,返回元组形式
print(result)

#关闭游标
cursor.close()
#关闭连接
conn.close()

注意:fetchone()有一个数据指针,获取一行,就会跳到下一行,不能返回。

实例:读取数据库,验证用户登录

#通过读数据库验证用户登录
import pymysql

username = input("请输入用户名:")
password = input("请输入密码:")
try:
    # 创建连接
conn = pymysql.Connect(host="127.0.0.1",
                       port=3306,
                       user="root",
                       password="123456",
                       database="study",
                       charset="utf8")
    # 创建游标,利用游标支数据库取数据
    cursor = conn.cursor()

    sql = 'select * from userinfo where username="%s" and password="%s" '%(username,password)
    cursor.execute(sql)
    result = cursor.fetchall()   #获取返回的全部数据,元组形式
    if result:
        print("登录成功")
    else:
        print("账号或密码错误")
except Exception as e:
    print(e)
    raise
finally:
    cursor.close()
    conn.close()

注意:以上代码有SQL注入的漏洞,请看如下演示
演示一:输入正确用户名和密码

第11天,Python操作MySQL
演示一

演示二: 输入用户名:alex" -- , 输入任意密码

第11天,Python操作MySQL
演示二

解析:由上图可以看出,用户名和密码都是错误的,也可以通过验证。这是为什么呢?我们来解析一下通过用户名和密码生成的SQL。通过字符串替换,我们可以得到这样一条SQL:select * from userinfo where username="alex" -- " and password="sdfsfsd"。从这条SQL可以看出,username="alex"后面被--注释了(--是SQL语言中的注释符),后面的语句就不能被mysql解析了,所以不管密码输入的是什么,都会被忽略掉。

演示三:输入用户名:xxx" or 1=1 -- , 输入任意密码

第11天,Python操作MySQL
演示三

解析:由上图可以看出,即使不知道数据库中的用户名和密码是什么,也可以通过验证。通过字符串替换,我们得到这样的一条SQL:select * from userinfo where username="xxx" or 1=1 -- " and password="asdffas"。这条SQL,1=1后面被注释了,而select * from userinfo where username="xxx" or 1=1是永远成立的,可以从数据库获取到值,所以可以通过验证。

改进版《读取数据库,验证用户登录》

防止被SQL注入

我们在输入SQL字符串时,不要自己去做字符串格式化替换,可以在给execute方法传参时,第一个参数传查询的SQL,第二个参数传SQL中要替换的字符串列表。pymysql模块内部会自动替换,在替换时,会将特殊字符替换掉。

#改进版

import pymysql

username = input("请输入用户名:")
password = input("请输入密码:")

try:
    # 创建连接
conn = pymysql.Connect(host="127.0.0.1",
                       port=3306,
                       user="root",
                       password="123456",
                       database="study",
                       charset="utf8")
    # 创建游标,利用游标支数据库取数据
    cursor = conn.cursor()

    sql = 'select * from userinfo where username=%s and password=%s '
    cursor.execute(sql,[username,password])   #第2个参数为列表
    result = cursor.fetchall()   #获取返回的全部数据,元组形式
    if result:
        print("登录成功")
    else:
        print("账号或密码错误")
except Exception as e:
    print(e)
    raise
finally:
    cursor.close()
    conn.close()

演示四:

第11天,Python操作MySQL
演示四

可以看出,代码改进后,就不会再出现被SQL注入了。

2.2.2 写库操作必须提交commit

对数据库进行增、删、改操作都必须执行提交(commit)操作

import pymysql

# 创建连接
conn = pymysql.Connect(host="127.0.0.1",
                       port=3306,
                       user="root",
                       password="123456",
                       database="study",
                       charset="utf8")

cursor = conn.cursor()

#执行SQL,返回值v是受影响的行数
sql = 'insert into userinfo(username,password) values(%s,%s)'
cursor.execute(sql,["eric","123321"])

#对数据库进行增、删、改操作都必须执行提交(commit)操作
conn.commit()
cursor.close()
conn.close()

2.2.3 直接获取新增数据的自增ID

cursor.lastrowid方法可以直接获取新增数据的自增ID

需求:现在我想往class班级表中新插入一个班级,然后再往这个新班级中插入一条学生数据(包含班级ID)。

import pymysql

# 创建连接
conn = pymysql.Connect(host="127.0.0.1",
                       port=3306,
                       user="root",
                       password="123456",
                       database="study",
                       charset="utf8")

cursor = conn.cursor()
cursor.execute('insert into class(caption) values("三年三班")')

new_class_id = cursor.lastrowid  #获取新增数据的自增ID
cursor.execute('insert into student(sname,gender,class_id) values(%s,%s,%s)',["李杰","女",new_class_id])

#对数据库进行增、删、改操作都必须执行提交(commit)操作
conn.commit()
cursor.close()
conn.close()

2.2.4 将查询结果以字典形式返回

需要在conn.cursor()传一个参数:conn.cursor(cursor=pymysql.cursors.DictCursor)

import pymysql
conn = pymysql.Connect(host="127.0.0.1",
                       port=3306,
                       user="root",
                       password="123456",
                       database="study",
                       charset="utf8")
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute("select * from class")
result = cursor.fetchall()
print(result)
cursor.close()
conn.close()

'''
输出结果:
[{'cid': 1, 'caption': '三年二班'}, {'cid': 2, 'caption': '一年三班'}, {'cid': 3, 'caption': '三年一班'}, {'cid'
'''
上一篇:第8天,面向对象进阶


下一篇:第12天,HTML基础