一、环境安装及运行
-
安装(ubuntu系统)
sudo apt-get install mysql-server mysql-client
根据提示,设置root用户的密码
-
管理服务
sudo service mysql start #开启 sudo service mysql stop #关闭 sudo service mysql restart #重启
-
允许远程连接
-
修改配置文件
sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf
将bind-address=127.0.0.1注释
-
重启mysql服务
sudo service mysql restart
-
登陆mysql
mysql -uroot -p
然后输入root账户密码
-
mysql中依次输入如下命令
grant all privileges on *.* to 'root'@'%' identified by '安装时设置的密码' with grant option; flush privileges;
-
退出
exit
-
重启mysql
-
二、用户操作
-
创建用户
-
通过root账号登陆mysql(用户操作均在root账号下进行)
mysql -uroot -p
然后输入root账号密码
-
创建用户,并赋予相应权限
grant all privileges on 数据库名.表名 to '用户名'@'主机名' identified by '密码' with grant option; flush privileges;
- 数据库名:*表示所有
- 表名:*表示该数据库下的所有表
- 数据库名.表名:*.*表示root权限,即满权限
- 主机名:localhost表示仅允许本地连接,%表示本地和远程均可连接
- flush privileges;表示刷新权限,使授权生效
-
示例:新建test用户,授予该用户的权限是仅能操作test_database数据库,密码‘123’
grant all privileges on test_database.* to 'test'@'%' identified by '123' with grant option; flush privileges;
-
-
修改用户密码
-
使用mysql数据库
use mysql;
-
修改用户密码(更新user这个表)
update user set authentication_string = password('新密码') where user = '用户名' and host = '主机名';
password()为mysql自身的一个加密函数
-
示例:修改test用户密码为'456'
update user set authentication_string = password('456') where user = 'test' and host = '%';
-
-
撤销用户权限
revoke all on 数据库名.表名 from '用户名'@'主机名'; flush privileges;
-
删除用户
drop user '用户名'@'主机名';
三、数据库操作
-
创建数据库
create database 数据库名 charset=utf8;
-
删除数据库
drop database 数据库名;
-
切换数据库
use 数据库名;
-
查看所有数据库
show databases;
-
查看当前所在数据库
select database();
-
数据库备份
-
切换至超级管理员
sudo -s
-
进入mysql库目录
cd /var/lib/mysql
-
运行mysqldump命令
mysqldump -uroot -p 需要备份的数据库名 > /path/备份文件名.sql #后面重定向的路径自定义
-
-
数据库恢复
-
连接数据库
mysql -uroot -p
-
创建数据库
create database 恢复后数据库名 charset=utf8;
-
退出
exit
-
从备份数据库中恢复
mysql -uroot –p 恢复后数据库名 < /path/备份文件.sql
-
四、表操作
-
查看当前数据库中所有表
show tables;
-
创建表
-
语法
create table 表名 (字段1 类型 约束,字段2 类型 约束...);
-
常见的字段类型
- float:单精度浮点型
- double:双精度浮点型
- decimal(m,d):比如decimal(5,2)表示最多5位数,小数位2位,可以存储1.2 但不能存储1000.21
- tinyint:小整数值,1byte,范围(0,255)
- int:大整数值,4bytes,范围(0,232-1)
- bigint:极大整数值,8bytes,范围(0,264-1)
- date:日期值,比如2020-10-10
- time:时间值,比如23:59:59
- datetime:混合日期和时间值,比如2020-10-10 23:59:59
- timestamp:时间戳
- bit:布尔类型,0和1两种状态
- char(n):定长字符串,不够位数,右侧补空格
- varchar(n):不定长字符串,最多能存储n个字符
- tinytext:短文本数据
- text:长文本数据
- tinyblob:不超过255个字符的二进制字符串
- blob:二进制形式的长文本数据
-
约束
- 主键:primary key
- 非空:not null
- 唯一性:unique
- 默认:default
- 外键:foreign key
-
示例:创建用户信息表
CREATE TABLE `user_info` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL, `age` tinyint(4) NOT NULL, `phone_num` char(11) NOT NULL, `gender` bit(1) DEFAULT b'1', PRIMARY KEY (`id`), UNIQUE KEY `phone_num` (`phone_num`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-
修改表的结构
-
添加字段
alter table 表名 add 字段名 类型;
-
修改字段名
alter table 表名 change 原字段名 新字段名 新字段类型;
-
修改字段类型
alter table 表名 modify 字段名 新类型;
-
删除字段
alter table 表名 drop 字段名;
-
-
查看表结构
desc 表名;
-
查看表的创建语句
show create table 表名;
-
更改表名
rename table 原表名 to 新表名;
-
删除表
drop table 表名;
五、数据操作
-
查询
-
基本语法
select * from 表名;
- from关键字后面写表名,表示数据来源于是这张表
- select后面写表中的列名,如果是*表示在结果中显示表中所有列
- select后面的列名部分,可以使用as为列起别名(as也可以省去),这个别名出现在结果集中
- 如果要查询多个列,之间使用逗号分隔
-
消除重复行
- 在select后面列前使用distinct可以消除重复的行
select distinct gender as '性别' from user_info;
- 如果distinct后面有多个列,那么只有多个列整行的内容都相同时才会消除重复
select distinct id,gender from user_info; #由于id不可能相同,所以不会消除重复
- 如果消除重复的语句后面有根据字段排序,则排序的字段也需要列在distinct后面(注:排序在后面有介绍)
select distinct name from user_info order by gender desc; #错误写法 select distinct name,gender from user_info order by gender desc; #正确写法
- 在select后面列前使用distinct可以消除重复的行
-
条件
- 使用where子句对表中的数据筛选,结果为true的行会出现在结果集中
select * from 表名 where 条件;
- 比较运算符
- 等于:=
- 大于:>
- 大于等于:>=
- 小于:<
- 小于等于:<=
- 不等于:!=
- 示例:
select * from students where isdelete=0; #查询没被删除的学生 select * from students where id>3; #查询编号大于3的学生 select * from subjects where id<=4; #查询编号不大于4的科目 select * from students where sname!='黄蓉'; #查询姓名不是“黄蓉”的学生
- 逻辑运算符
- and
- or
- not
- 示例:
select * from students where gender=0 and id>3; #查询编号大于3的女同学 select * from students where isdelete=0 or id<4; #查询编号小于4或没被删除的学生
- 模糊查询
- like
- %表示任意多个任意字符
- _表示一个任意字符
- 示例:
select * from students where sname like '黄%'; #查询姓黄的学生 select * from students where sname like '黄_'; #查询姓黄并且名字是一个字的学生 select * from students where sname like '黄%' or sname like '%靖%'; #查询姓黄或者名字中含有靖的学生
- 范围查询
- in表示在一个非连续的范围内
- between ... and ...表示在一个连续的范围内
- 示例:
select * from students where id in(1,3,8); #查询编号是1,3,8的学生 select * from students where id between 3 and 8; #查询编号是3-8的学生
- 空判断
- 注意:null与空字符串''是不同的
- 判空is null
- 判非空is not null
- 示例:
select * from students where hometown is null; #查询没有填写地址的学生 select * from students where hometown is not null and gender=0; #查询填写了地址的女生
- 使用where子句对表中的数据筛选,结果为true的行会出现在结果集中
-
聚合
-
聚合能够快速得到统计数据,以下提供了5个聚合函数:
- count(*):表示计算总行数,等同于 count(字段)
- max(字段):表示求此字段的最大值
- min(字段):表示求此字段的最小值
- sum(字段):表示求此字段的和
- avg(字段):表示求此字段的平均值
- 示例:
select count(*) from students; #查找学生总数 select max(age) from students where gender=0; #查询女生最大年龄 select min(id) from students where isdelete=0; #查询未删除的学生最小编号 select sum(id) from students where gender=1; #查询男生的编号之和 select avg(age) from students where gender=1; #查询男生的平均年龄
-
-
分组
- 按照字段分组,表示此字段相同的数据会被放到一个组中,实质是合并行,分组的目的一般是为了进行数据统计,做聚合运算
- 语法:
select 列1,列2,聚合... from 表名 group by 字段1,字段2,字段3...
- 示例:
select gender as 性别, count(*) as 人数 from students group by gender; #查询男女生人数
- 分组后数据筛选
- 语法
select 列1,...聚合... from 表名 group by 字段1,...having 条件;
having后面的条件运算符与where的相同,但是选择集不同,where是对from后面指定的表进行数据筛选,属于对原始数据的筛选,having是对group by的结果进行筛选
- 示例:
select gender as 性别, count(*) as 总数 from students group by gender having gender=1; #查询男生人数
- 语法
-
排序
- 为了方便查看数据,可以对数据进行排序
- 语法
select * from 表名 order by 字段1 asc|desc,字段2 asc|desc,...
- 将行数据按照字段1进行排序,如果字段1的值相同时,则按照字段2排序,以此类推
- asc:从小到大排列,即升序,默认就是按照这种方式排列
- desc:从大到小排序,即降序
- 示例:
select * from students where gender=1 order by id desc; 按学号降序查询男生信息
-
获取部分行数据
- 当数据量过大时,在一页中查看数据是一件非常麻烦的事情
- 语法
select * from 表名 limit start,count;
从start开始,获取count条数据,start索引从0开始,如果不写start,则默认start=0,表示从第1个数据开始,获取count条
- 分页功能的实现
- 比如每页有m条数据,显示第n页的数据
select * from 表名 where... limit (n-1)*m, m;
如果第n页数据不足m条,则显示当前页的实际条数
- 比如每页有m条数据,显示第n页的数据
-
总结
- 完整的查询语句:
select distinct * from 表名 where .... group by ... having ... order by ... limit star,count;
实际使用中,只是语句中某些部分的组合,而不是全部
- 完整的查询语句:
-
-
插入
-
全列插入单条数据
insert into 表名 values(0,...);
主键列是自增的,但是在全列插入时需要占位,通常使用0,插入成功后自动会添上正确的数值
-
全列插入多条数据
insert into 表名 values(0,...),(0,...)...;
-
缺省插入单条数据
insert into 表名(字段1,...) values(值1,...);
-
缺省插入多条数据
insert into 表名(字段1,...) values(值1,...),(值1,...)...;
-
-
修改
update 表名 set 字段1=值1,... where 条件...;
-
删除
delete from 表名 where 条件;
-
逻辑删除(本质上是修改操作)
# 通常会增加一个字段isdelete,默认为0 alter table 表名 add isdelete bit default 0; # 如果需要删除则修改isdelete=1 update 表名 set isdelete=1 where ...;
六、外键
-
认识外键
- 在存储关系的表中添加字段,为该字段创建外键来引用另一个表的主键,从而建立关系
- 通过外键约束进行数据的有效性验证,当添加或修改的数据不是引用另一个表的主键时,则报错
-
创建外键
-
创建表的时候直接创建约束
create table scores( id int primary key auto_increment, stuid int, subid int, score decimal(5,2), foreign key(stuid) references students(id), foreign key(subid) references subjects(id) );
-
添加外键约束
alter table 表名 add constraint 约束名 foreign key(字段名) references 主表名(id); #其中约束名可以任意起 alter table scores add constraint stu_sco foreign key(stuid) references students(id);
-
-
删除外键
-
先查找出约束名
show create table 表名;
-
根据约束名进行删除
alter table 表名 drop foreign key 约束名;
-
-
外键的级联操作
-
级联操作的类型包括:
-
- restrict(限制):默认值,抛异常
- cascade(级联):如果主表的记录删掉,则从表中相关联的记录都将被删除
- set null:将外键设置为空
- no action:什么都不做
-
删除主表中数据,如果该数据的id在从表中已经存在,则会抛异常,解决办法:
- 使用逻辑删除(推荐)
- 修改外键的级联操作
alter table 表名 add constraint 约束名 foreign key(字段名) references 主表名(id) on delete 级联操作类型; alter table scores add constraint stu_sco foreign key(stuid) references students(id) on delete cascade;#主表数据删掉,从表中相关联记录都将删除
-
七、连接查询
当查询的结果来源于有关系的多张表时,需要使用到连接查询
-
连接查询分类:
- 内连接(inner join):表A inner join 表B,表A和表B都匹配的行出现在结果集当中(不区分两个表的先后顺序)
- 左连接(left join):表A left join 表B,表A与表B都匹配的行会出现在结果中,外加表A中独有的数据,未对应的数据使用null填充(区分先后顺序)
- 右连接(right join):表A right join表B,表A与表B都匹配的行会出现在结果中,外加表B中独有的数据,未对应的数据使用null填充(区分先后顺序)
-
连接查询中字段名和表名的使用:
- 在查询或条件中推荐使用“表名.字段名”的语法
- 如果多个表中字段名不重复,则可以省略"表名."部分,直接使用"字段名"
- 如果表的名称太长,可以取个简写别名,表名后面使用"as 简写名"或者省去as,直接跟上“简写名”
-
示例:
-
查询学生的姓名、总分
select students.sname 姓名,sum(scores.score) 总分 from scores inner join students on scores.stuid=students.id group by students.sname;
- 查询每个学生每个科目的成绩
select students.sname 姓名,subjects.stitle 科目,scores.score 成绩 from scores inner join students on scores.stuid=students.id inner join subjects on scores.subid=subjects.id;
-
八、自关联
-
什么是自关联
- 表中的某一列,通过外键引用了本表的另外一列(主键),但是它们的业务逻辑含义又是不一样的,这就是自关联
- 物理上一张表,逻辑上是多张表,必须通过取别名来区分,能够节省表的开销
-
应用场景
- 比如设计了这样的两张表:省(provinces)信息的表结构(id,ptitle)和市(cities)信息的表结构(id,ctitle,pid),其中pid对应着provices表的id。通过比较发现,cities表比provinces表多一个列pid,其它列的类型都是一样的,存储的都是地区信息,而且每种信息的数据量有限,因此没必要增加一个新表,或者将来还要存储区、乡镇信息,都增加新表的开销太大。我们可以重新设计一个地区(areas)信息的结构(id,atitle,pid),因为省没有所属的省份,所以pid可以填写null,城市所属的省份pid可以填写省所对应的id。在这个表中,结构不变,还可以添加区县、乡镇街道、村社区等信息。
-
示例:
- 查询山西省的所有市名
select province.atitle 省名,city.atitle 市名 from areas as province inner join areas as city on province.id = city.pid where province.atitle = '山西';
- 查询山西省的所有市名
-
总结
- 对于省市区、商品分类等这种结构上相同(或相近),并且具有包含关系的多张表,我们可以按照自关联的方式给设计成一张表,能够节省表的开销
九、子查询
-
子查询
- 嵌套在其它查询中的查询
-
分类:
-
where型子查询:
- 把子查询的结果当做外层查询的一个比较条件,单个值前面使用比较运算符,多个值使用in
- 查询山西省的所有市名
select atitle 市名 from areas where pid = (select id from areas where atitle = '山西省');
- 查询男女生编号最大的学生信息
select * from students where id in (select max(id) from students group by gender);
-
from型子查询:
- 把子查询的结果当做临时表,需要取别名
- 查询所有男生的信息,并且给每条信息添上行号
select @rownum:=@rownum+1 rownum,name,age from (select name,age from students where gender=1) stu,(select @rownum:=0) row;
注:@变量名:=value是给变量赋值,from后面两个临时表用','隔开,表示全相乘
-
exists型子查询:
- 首先执行外层查询,再执行内层查询,如果内层查询结果为真,则取出该行,以此类推,直到整个表查询结束
- 查询商品分类表中有商品的分类信息
select name from category as cat where exists(select 1 from goods where goods.cat_id = cat.id );
-
计算字段型:
- 首先执行外层查询,再执行内层查询,如果内层查询到结果,则显示在结果行中,未查询到,则该字段查询结果为NULL
- 查询各学生的数学成绩
select name as 姓名,(select score from scores inner join subjects on scores.sub_id = subjects.id where subjects.title = '数学' and stu_id = stu.id) as '数学' from students stu;
-
-
总结:
- 能够使用连接查询,就不要使用子查询,因为子查询会增加查询的次数
十、视图
-
视图
- 对于复杂的查询,在多次使用后维护起来比较麻烦,我们可以通过定义视图的方式来解决。
- 视图的本质就是对复杂的查询语句进行封装,相当于生成了一个新的表,它的用途就是查询。
-
创建视图
create view 视图名 as select ...
通常视图名以v_开头便于区分
-
查看视图
show tables;
同查看表的操作相同
-
修改视图
alter view 视图名 as select ...;
-
使用视图
select * from 视图名;
十一、事务
-
事务
- 当一个业务需要多个操作步骤(insert ino | update | delete from)时,只有所有步骤都完成才算完成,如果其中某条sql语句出错,则整个操作都退回。
- 使用事务可以完成退回的功能,从而保证业务逻辑的正确性。
- 事务的本质是:上锁
-
事务的四大特性:
- 原子性(Atomicity):事务中的全部操作在数据库中是不可分割的,要么全部完成,要么均不执行
- 一致性(Consistency):几个并行执行的事务,其执行结果必须与按某一顺序串行执行的结果相一致
- 隔离性(Isolation):事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的
- 持久性(Durability):对于任意已提交事务,系统必须保证该事务对数据库的改变不被丢失,即使数据库出现故障
-
要求:
- 表的引擎类型必须是innodb或bdb类型
-
修改表的类型:
- 查看表的创建语句,来查看表的引擎类型
show create table 表名;
- 修改表的类型
alter table 表名 engine=innodb;
- 查看表的创建语句,来查看表的引擎类型
-
事务操作步骤
- begein:开启事务,并在内存级临时表中进行增、删、改等操作
- commit:将临时表中的数据更新到原表中,确认更改,释放锁
- rollback:放弃begin后面的所有操作,释放锁
- 注意:commit和rollback操作2选1
-
示例:
begin; insert into students(name,age,gender) values('张三',25,1); update students set age=28 where name='李四'; delete from students where name='王五'; commit; #或者rollback;
十二、索引
-
索引
- 针对数据库中现有的数据,整理出一块物理存储下来的用于快速查找数据用的的东西。
- 数据库中实际数据的存储会按照某种索引,默认是按照主键(特殊的索引),并且数据物理结构上的存储顺序也是按照主键的顺序。
- 索引的创建会增大物理上的开销。
-
创建索引时如何选择字段数据类型?
- 数据类型小:越小的数据类型通常在磁盘、内存和CPU缓存中都需要更少的空间,处理起来更快。能用bit类型,不用int,能用int,不用decimal.
- 数据类型简单:整形数据比起字符,开销更小
- 尽量避免NULL:含有NULL的列,很难进行查询优化,你可以用0,空字符串' '或者一个特殊的值去代替。
-
什么时候考虑创建索引?
- 一开始做项目的时候,通常不会去考虑对数据库创建索引这件事,因为没有大量的数据作为基础,建立索引区别不大。当系统上线运营了一段时间后,数据库中数据量达到一定规模时我们可以进行监测,当发现检索速度变慢(比如大于100ms)时,我们就需要去分析业务逻辑中sql语句where后面的判断字段,针对这些字段建立索引进行优化。
-
建立索引对sql语句的编写有什么要求?
- 将'='值的条件尽量写在前面,表示范围的比如'>'尽量写在后面,尽量避免使用'or',否则建立索引对优化查询速度已经没有意义了
-
索引操作:
-
建立索引
create index 索引名 on 表名(字段名1,...);
如果只有一个字段名,表示建立单列索引;多个字段名,表示建立组合索引。如果字段为字符类型,可以在字符后面指定长度,比如students(name(20),age),也可以不指定,其他类型(int,bit)的字段不需要指定长度
-
查看索引
show index from 表名;
-
删除索引
drop index 索引名 on 表名;
-
-
索引缺点
- 虽然索引会提升查询的速度,但同时会降低更新表(insert into|delete from|update)的速度,因为更新表的时候还要保存一下索引文件
- 建立索引,会占用磁盘空间的索引文件
-
性能监测工具profiles的使用
-
仅限于当前数据库的本次连接,下次连接失效
-
示例:
set profiling = 1; #开启监测工具 select * from areas where atitle = '北京市'; #执行查询语句 show profiles; #查看查询执行时间 create index title_index on areas(atitle); #为atitle字段创建索引 select * from areas where atitle = '北京市'; #再次执行查询语句 show profiles; #再次查看执行时间
-
十三、与python交互
-
安装及引入模块
-
安装PyMySQL模块
pip3 install PyMySQL
-
脚本中引入模块
import pymysql
-
-
Connection对象
-
用于建立与数据库的连接
-
创建对象:
- 调用pymysql.connect()方法
conn = pymysql.connect(host="主机",port=3306,user="用户名",passwd="密码",db="数据库名",charset="utf8")
如果是本机,host填'localhost',port端口号,默认3306,charset字符编码,默认是'gb2312',要求与数据库创建时指定的编码一致,否则中文会乱码
- 方法:
- commit()
- 提交事务,使操作生效,在执行select查询任务时,则不需要这一步
- rollback()
- 回滚事务,放弃之前的操作
- cursor()
- 创建cursor对象,用于执行sql语句
- close()
- 关闭连接
- 调用pymysql.connect()方法
-
-
Cursor对象
-
用于执行sql语句,默认开启了事务(begin)
-
创建对象:
- 调用Connection对象的cursor()方法
cur = conn.cursor()
- 调用Connection对象的cursor()方法
-
方法:
- execute(sql,[,parameters])
- 执行语句,返回受影响的行数,第二个参数可选,元组或列表类型,参数化可以防止sql注入风险,sql语句中使用%s作为占位符,可以表示任何数据类型。
- fetchone()
- 执行查询语句时,获取查询结果集的第一个行数据,返回一个元组,未查到,则返回None。如果结果集不止一条数据,可以再次执行fetchone()获得第二个行数据,依此类推
- fetchall()
- 执行查询时,获取结果集的所有行,一行构成一个元组,再将这些元组装入一个元组返回,未查到,则返回空元组()。可以与fetchone()方法搭配使用,比如可以先fetchone()查询一条数据,然后执行fetchall()查询剩下所有数据。
- scroll(value[,mode])
- 将行指针移动到某个位置。mode表示移动的方式,默认值为'relative',value表示基于当前行向上(取负值)或向下(取正值)移动的行数。当mode的值为‘absolute’,value表示基于第一行数据(位置为0)向下移动的行数。
- close()
- 关闭cursor
- execute(sql,[,parameters])
-
属性:
- rowcount只读属性,表示最近一次execute()执行后受影响的行数
- connection获得当前连接对象
-
-
增、删、改、查操作
-
增、删、改操作大致流程
- 导入模块:import pymysql
- 创建connection对象,与数据库建立连接:con = pymysql.connect(...)
- 创建cursor对象:cur=con.cursor()
- 执行增、删、改sql语句(可以连续执行多条):cur.execute(sql)
- ......
- 提交或回滚事务:con.commit()或者con.rollback()
- 关闭cursor:cur.close()
- 关闭connection连接:con.close()
-
查找操作大致流程
- 导入模块:import pymysql
- 创建connection对象,与数据库建立连接:con = pymysql.connect(...)
- 创建cursor对象:cur=con.cursor()
- 执行sql语句(可以连续执行多条):cur.execute(sql)
- 获取查询结果:cur.fetchone()或者cur.fetchall()
- 关闭cursor:cur.close()
- 关闭connection连接:con.close()
-
比较查找操作和增删改操作的区别(多一步,少一步):
- 多一步:查找操作在执行sql语句后,需要通过fetchone()或者fetchall()方法来获取查询结果
- 少一步:查找操作不需要提交或回滚事务
-
示例:
- 增加、修改、删除一条学生表数据
# coding = utf-8 import pymysql con = pymysql.connect(host='localhost',port=3306,user='root',password='123',db='test',charset='utf8') # 创建connect对象 cur = conn.cursor() #创建cursor对象 name = input('请输入添加的学生姓名:') sql1 = 'insert into students(name) values(%s);' sql2 = 'delete from students where name = "老王";' sql3 = 'update students set name = “老张” where name = "老李";' try: cur.execute(sql1,[name]) #增加一条数据 cur.execute(sql2) #删除一条数据 cur.execute(sql3) #修改一条数据 except Exception as e: print(e) con.rollback() # 放弃之前的所有操作 else: con.commit() # 提交,使所有操作生效 cur.close() # 关闭cursor对象
- 查找学生信息
# coding = utf-8 import pymysql con = pymysql.connect(host='localhost',port=3306,user='root',password='123',db='test',charset='utf8') # 创建connect对象 cur = conn.cursor() #创建cursor对象 try: sql = 'select * from students;' count = cur.execute(sql) data1 = cur.fetchone() #查找第一行数据 print(data1) data2 = cur.fetchall() # 查找剩下所有行数据 print(data2) except Exception as e: print(e) cur.close() con.close()
- 增加、修改、删除一条学生表数据
-