python 十周周末总结 MySQL的介绍与使用
MySQL字符编码与配置文件
- 查看数据库的基本信息(用户,字符编码)
- /s
- windos下MySQL默认的配置文件
- my_default.ini
- 修改配置文件名称(必须要带my和ini后缀否则不会被识别)
- my.ini
- 修改mysql服务器默认字符编码(我们需要重新启动我们之前设置的自启服务器)
- [mysqld]\n character-set-server=utf8(字符编码即可)\n collation-server=utf8_general_ci
- 修改客户端默认的字符编码(只需要推出客户端重新进即可)
- [client]\n default-charcter-set=utf8
- 修改MySQL的字符编码,同上方那个一样都只需要重新进即可
- [mysql]\n default-character-set=utf8
- 偷懒操作(不需要登录)
- 直接在修改的配置文件中写入自己的账号和密码即可
MySQL存储引擎
- MyISAM 引擎
- MySQL5.5及之前版本默认的存储引擎,存取速度较快,但是安全性较低
- InnoDB 引擎
- MySQL5.5之后版本的默认存储引擎,存取速度较慢,但是安全性较高,并且支持事务,行锁,外键等诸多功能
- Memory 引擎
- 给予内存工作的引擎存取速度极快,但是断电那么数据就会立即丢失
- BlackHole 引擎(黑洞)
- 无论写入什么东西都会立即丢失,可以当做一个垃圾回收站
- 展示引擎效果
- insert into 表名 values(1);
- 查看内部所有引擎
- show engines;
创建表的完整语法
- 字段名和字段类型是必须的
- 数字和约束条件是可选的(可有可无)
- 约束条件可以写多个 只要空格隔开即可
- 最后一个字段的结尾千万不能加逗号
create table 表名(
字段名1 字段类型(数字) 约束条件,
字段名2 字段类型(数字) 约束条件,
字段名3 字段类型(数字) 约束条件
);
字段类型之整型
-
tinyint 存储一个字节
-
smallint 存储两个字节
-
mediumint 存储三个字节
-
int 存储四个字节
-
bigint 存储八个字节
-
验证整型是否自带负号
cerate table 表名(字段名 tinyint); insert into 表名 values(-129),(256); 发现自动填写为两个边界值,数据失真久没有任何意义了 上述所有类型默认都会带有负号
-
自定义移除负号
""" unsigned 约束条件之一 意思是不需要负号 """ create table 表名(字段名 tinyint unsigned); insert into 表名 values(-129),(256);
-
修改文件
插入的数据值超出了数据类型的范围 不应该让其插入并自动修改 没有任何意义 数据库应该直接报错(这个特性其实应该是有的但是我们做配置文件的时候被我们修改了) 方式一: set session sql_mode='strict_trans)tables' 当前客户端操作界面有效 set global sql_mode='STRICT_TRANS_TABLES' 服务器不重启那么就永久有效 方法二: [mysqld] sql_mode='STRICT_TRANS_TABLES' 其实和上方编写配置文件的的一样,只是将我们需要一直写的东西直接写入了就不需要我们自己去输入了
字段类型之浮点型
- float 可以存储小数点后六到七位
- double 后很多位一般用不到
- decimal 后很多位一般用不到
字段类型之字符类型
- char 存储固定的字符如果超过那么直接报错
- varchar 存储固定的字符如果超过那么直接报错
数字的含义
- 数字在大多数情况下都是为了限制字段的存储长度,但是整形排除在外,不是用来限制存储的长度,而是他给你多少数字那么你就需要接受多少数字
字段类型之枚举与集合
- neum枚举类型是一种可以在实现定义好的哥哥可取纸中选择一个的数据类型,其定义方法使用enum来定义此种类型后,酱油相关字段的取值范围进行了限制,只能去枚举值中的一个否则就会报错,一个枚举类数据最多可以有65535个枚举项
- 集合其实就是可以在内部取多个值,也就是多嫌多(多选一也可以叫做集合)
字段类型之日期类型
- date 年月日
- datetime 年月日时分秒
- time 时分秒
- year 年
- eleate now();展示现在时间
字段的约束条件
-
unsigned 无负号
-
zerofill 零填充
-
not null 非空
-
unique 唯一性
unique(两个或多个条件) 联合唯一
约束条件之主键
- 在InnoDB引擎中规定只要是使用这个引擎就必须要有一个主键,单从约束角度上而言的话主键其实就是非空且唯一 not null unique(非空且唯一),如果你自己没有设置主键的话那么引擎就会自动帮你设置一个隐藏主键,主键其实就像是我们新华字典中的目录可以帮我们迅速查找我们所需要的资源,主键一般是我们设置的id字段,主键也可以使用另一含义代表(primary key)主键
1.1非空且唯一 not null(非空) unique(唯一性)
create table t1(
id int primary key,
name varchar(32)
);
desc ti; # id key PRI
1.2测试主键
create table t2(
nid int not null unique,
sid int not null unique,
uid int not null unique,
name varchar(32)
);
desc t2; # nid key PRI sid key UNI uid key UNI
1.3补充,在创建表的时候都应该有一个'id'字段,并且该字段应该作为主键例如:id, nid, sid, uid, pid, gid, cid等;
id int primary key 单例主键
nid int,
sid int,
primary key(nid,sid) 联合主键
自增
-
auto_increment自增
- 在我们使用自增的时候必须要注意他是不可以单独自己使用的必须要跟在一个键的后面,并且这个自增如果我们删除了一个数据,他并不会按照规则补进去而是记住已经使用过的自增数,然后使用下一个自增
1.1自增(错误演示) create table t3( id int auto_increment ); # 直接使用的话那么就会报错,there can be only one auto column and it must be defined sa a key 1.2自增(正确演示) create table t4( id int primary key auto_increment, name varchar(32) ); 1.3删除与重装格式化 delete from(删除) truncate 表名; # 删除内部数据并且充值主键值
约束条件之外键
- 外键(froeign key)
- 使用方法
- froegin key (表数据) references 表名(id)
- 外键字段姿势就是用来记录表与表之间的数据关系,而数据之间的关系则有四种
- 单对多关系
- 多对多关系
- 单对单关系
- 没有关系
- 表数据关系的判断其实就是根据换位思考的方式来判断对方是什么关系
约束条件之一对多
-
一对多外键字段
1.在我们将表与表之间进行关联的时候就需要使用外键来当作他的两个表之间的记录关系。 2.一 create table dep( id int primary key auto_increment, dep_name varchar(32), dep_desc varcahar(32) ); 3.多 create table emp( id int primary key auto_increment, name varchar(32), gender enum('amle','female','others')default'male', dep_id int, froeign key(dep_id)references dep(id) ); 4.补充 4.1创建表的时候需要先创建被关联的表(没有外键的表)然后才能创建有关联的表(有外键),如果我们先创建有关联的表那么就会因为苦衷没有该被关联的表然后报错,不符合逻辑,所以我们需要先创建无关联的表然后再进行关联表的创建 4.2在我们插入数据的时候,针对外键字段只能够填充被关联字段中出现过的数据值,如果没有出现的话,那么就会因为没有这个检索而报错 4.3被关联的字段无法进行修改和删除
-
级联更新,级联删除
1.我们既然需要关联那么我们就需要这边改完数据然后那边也改,但是这样比较麻烦并且我们的还是关联的文件没办法直接修改所以我们就需要级联更新,修改一个那么和他有关联的全部都修改 1.1级联更新,级联删除 create table dep( id int primary key auto_increment, dep_name varchar(32), dep_desc varchar(32) ); create table emp1( id int primary key auto_increment, name varchar(32), gender enum('male','female','others')default 'male', dep_id int, froeign key(dep_id) references depl(id) on update cascade on delete cascade ); 2.补充 2.1我们在实际工作中,很多地方可能并不会使用外键,因为外键增加了表之间的耦合度,不便于操作,资源消耗增加,并且如果全部使用外键那么会导致修改一个数据然后整个数据系统就像翻新了一样,导致不便 2.2我们为了能够描述出表数据之间的关系,又不想使用外键的话就应该自己写SQL,自己建立代码层面的关系
约束条件之多对多
-
外键的多对多关系其实就是因为我们引用外键需要先将另外一个表放进去才可以写入有外键的表,但是由于两个表都有对方的外键所以都不能存放那么我们就需要对它进行解决也就是创建第三个表,然后使用第三个表来存储他们两个之间的关系
-
站在书籍的角度来看
- 一本书的作者信息能不能对应多条作者数据,也就是说一本书能不能有多个作者
- 可以
-
站在作者的标度来看
- 一个作者能不能对应很多本书的信息,也就是说一个作者能否写很多本书
- 可以
create table book( id int primary key auto_increment, title varchar(32), author_id int, foreign key(author_id) references author(id) on update cascade on delete cascade ); create table author( id int primary key auto_increment, name varchar(32), book_id int, foreign key(book_id) references book(id) on update cascade on delete cascade ); """ 双方互相调用好像不太行的样子 """
-
那么我们的这两张表其实有很多信息都是可以对应起来的并且有可能重叠对应,那么我们就可以称之为多对多关系
- 多对多这种关系在建立外键字段的时候不能建在这两个表的任何一个或者都建,否则没有办法申请创建这两个表,那么这个时候我们就需要创建第三个表来将这两个表的关系连接到一起实现多对多关系
create table book( id int primary key auto_increment, title varchar(32) ); create table author( id int primary key auto_increment, name varchar(32) ); create table bookandauthor( id int primary key auto_increment, book_id int, foreign key(book_id) references book(id) on update cascade on delete cascade, author_id int, foreign key(author_id) references author(id) on update cascade on delete cascade );
约束条件之一对一
- 一对一的关系其实和我们一对多差不多,但是我们也必须要寻找一个约束条件来关联两张表,这个时候我们就需要选择一个使用一个查询频率较高的表来存放外键,以方便使用
create table user(
id int primary key auto_increment,
name varchar(32),
detail_id int unique,
foreign key(detail_id) references userDetail(id)
on update cascade
on delete cascade
);
create table userDetail(
id int primary key auto_increment,
phone bigint
);
操作表的SQL语句补充
- 修改表名
- alter table 表名 reame 新表名
- 新增表中数据
- alter into 表名 add 字段名 字段类型(数字) 约束条件;
- alter into 表名 add 字段名 字段类型(数字) 约束条件 after 已存在的字段;
- alter into 表名 add 字段名 字段类型(数字) 约束条件 frist;
- 修改字段
- alter table 表名 change 旧字段 新字段 字段类型(数字)约束条件;
- alter table 表名 modify 字段名 新的字段类型(数字)约束条件;
- 删除字段
- alter table 表名 drop 字段名;
查询关键字之select与from
-
用法
select 自定义查询表中的数据 from 表名
-
在SQL语句中关键字编写顺序和执行顺序不太一样,首先是from从哪里拿到一张表然后select拿到表里的什么东西
查询关键字之where筛选
- 其实就是我们在SQL语句后面的约束条件进行筛选
查询关键字之group by 分组
- 其实就是如果我们的表中出现了很多重复的东西然后我们可以将按照分组的方式将他们都存储到一起我们可以根据这个分组来找到它内部的数据
查询关键字之having过滤
- 其实就是在分组的后面再加一层筛选,使数据变得更加详细,精确
查询关键字之distinc去重
- 其实就是去除重复的也就是一模一样的数据
查询关键字之order by 排序
- order by 内排序关键字
- asc 升序
- desc 降序
查询关键字之limit分页
- 就像我们浏览器的展示页面一样一次只展示多少种东西进行分页处理,在MySQL中也可以将自己的表设置展示页数那么就是用limit
- 语法
- select * from 表名 limit 5,5;
查询关键字之regexp正则
- 关键字regexp 调用正则
子查询
- 子查询其实就是我们根据上一步操作所然后来实行下一步操作,将两步操作拼起来我们还可以使用as给上一步操作起别名
连表查询
- inner join 内连接
- left join 左连接
- right join 右连接
- union 全连接
Navicat的下载与安装
-
下载地址
http://www.navicat.com.cn/download/navicat-premium
- 由于navict的功能非常强大所以navicat是收费的,我们下载并使用的话是需要收取费用的,但是我们可以先试着适用他的14天体验一下感觉
- 但是我们作为程序员的话,可以稍微修改一点东西让他试用实践较长一点
- 链接:https://pan.baidu.com/s/1aIKFM8oUpcTJX8cw3mVTsQ?pwd=e5y5 提取码:e5y5
- 我们可以通过这个注册机将navicat变成试用实践长一点
- 通过注册机获得注册码然后试用一下
Navicat的基本使用
- 连接
- 我们使用navicat必须先和自己的mysql数据库建立连接然后才能使用,点击连接选择mysql
- 然后连接名个人使用的时候不需要填,主机的话我们如果在公司的话那么我们会使用公司的主机码,如果个人的话,不动即可
- 端口我们mysql默认的端口就是3306这个不需要修改
- 用户名和密码填上我们默认的root或者自己设置的用户名和密码即可
- 点击测试连接,连接成功后确定那么我们就和自己的mysql连接成功
- 查看数据库
- 双击自己的连接即可,我们就可以看到我们之前创建或者系统自带的一些数据库
- 注意:有一个数据库information_schema是一个基于内存创建的数据库,所以我们在文件夹中是看不到他的实体的但是我们在mysql中是可以使用到他的
- 接下来进入表进入数据库等几乎不需要我们使用mysql代码来进入直接双击然后选择就可以进行操作,但是我们不能太过依赖这种方式,一定要把mysql的操作练的炉火纯青的时候才可以放心去使用
- 导入数据库
- 我们如果有别的数据库文件导入本数据库的话那么我们可以点击我们的数据库右键选择运行数据库选择文件运行即可,但是巡行的时候记得选择utf-8
- 查看数据库之间各表的关系
- 右键点击我们的数据库,选择逆向数据库到模型,那么我们就可以查看到各个数据库之间的关系
- 我们可以在这个内部来查看各数据库之间的关系然后来梳理关系,帮助我们编写代码
- 注释
- -- 注释,可以使用快捷键ctrl+?
- *‘ #’ 注释 常用的注释只有井号前面后面那个是为了防止markdown语法
- /**/ 注释
navicat实操
、查询所有的课程的名称以及对应的任课老师姓名
-- 首先查看老师列表和课程列表
-- select * from teacher;
-- select * from course;
# 查看到一共有四门课,然后有五名老师然后通过课程表和老师表的关系来查看关系
SELECT
course.cname,
teacher.tname
FROM
course
INNER JOIN teacher ON teacher_id = teacher.tid;
2、查询平均成绩大于八十分的同学的姓名和平均成绩
-- 2、查询平均成绩大于八十分的同学的姓名和平均成绩
-- 首先我们应该查看我们需要的表的对应关系(成绩表,学生表,课程表)
-- select * from student;
-- select * from course;
-- select * from score;
# 然后发现他们的表关系是多对多,都需要成绩表来连接他们之间的关系
/*先将所有学生进行分组,利用子连接拿到学生id和平均值*/-- select student_id from score group by student_id;
-- select student_id,avg(num) from score group by student_id having avg(num) > 80;
# 然后获取学生姓名
SELECT
student.sname,
t1.avg_num
FROM
student
INNER JOIN ( SELECT student_id, avg( num ) AS avg_num FROM score GROUP BY student_id HAVING avg( num ) > 80 ) AS t1 ON student.sid = t1.student_id;
3、查询只单独报了李平老师一门课的学生姓名
-- 还是查看相关的表有什么
-- select * from teacher;
-- select * from course;
-- select * from score;
-- SELECT * FROM student;
# 根据李平老师编号获取教授哪几个课程
-- select teacher.tname,course.teacher_id from teacher.tname inner join course on teacher.tid=course.teacher_id ;
# 获取一下成绩表
select sname from student where sid not in(select distinct sid from score where course_id in(select cid from course where teacher_id=(select tid from teacher where tname='李平老师')));
4、查询没有同时选修物理课程和体育课程的学生姓名
-- select * from student;
-- select * from score;
-- select * from course;
# 获取物理和体育课程的编号
-- select cid from course where cname in ('物理','体育');
# 获取成绩中的学生编号
-- select sid from score where course_id in ( select cid from course where cname in ('物理','体育'));
# 获取到有报过物理和体育的所有学生
select sname from student where sid in(select score.student_id from score where course_id in (select cid from course where cname in ('物理','体育')group by score.student_id having count(score.course_id)=1);
5、查询挂科超过两门(包括两门)的学生姓名和班级
-- 5、查询挂科超过两门(包括两门)的学生姓名和班级
select * from score;
select * from student;
select * from class;
-- select * from score where num < 60;
select student_id from score where score.num < 60 group by student_id having count(student_id) = 2;
select * from student where sid=(select student_id from score where score.num < 60 group by student_id having count(student_id) >= 2);
SELECT
class.caption,
student.sname
FROM
class
INNER JOIN student ON class.cid = student.class_id
WHERE
student.sid IN ( SELECT student_id FROM score WHERE num < 60 GROUP BY student_id HAVING count( student_id ) >= 2 ));
python操作MySQL的基本方法
1.我们要是使用python操作mysql就需要下载一个第三方模块:pymysql
2.下载方式:pip3 install pymysql
3.固定格式
impot pymysql
coon = pymysql connect( #连接服务器
host='127.0.0.1', #本机地址
port=3306, #服务端口
user='root', # 用户账号
password='密码', # 密码
datebase='库名', # 库名
charset='utf8md4', # 编码格式
autocommit=True # 二次确认,没有二次确认则不会更改数据
)
cursor = conn.cursor(cursor=pymysql.cursor.DictCursor) #产生一个游标对象,然后等待输入命令
sql1 = 'SQL语句' # 编写SQL语句
cursor.execcute(sql1) # 发送给服务端
res = cursor.fetchall() # 获取执行结果
print(res) # 打印结果
python中获取结果的注意事项
1.增
insert_form有三种
insert当有与主键相同的值插入时,不会插入数据并报错
insert.ignore当有与主键相同值插入时,忽略该记录不插入但是不报错
replace 当有与主键相同值插入时,删除原有记录重新插入新纪录值
def insert_data(insert_form, insert_table):
sql_insert = """{} into {}(id,name,number) values(%s,%s,%s)""".format(insert_form, insert_table)
cur.execute(sql_insert % (1,'lewis',44))
conn.commit() # 一定不能忘记commit
cur.close()
conn.close()
print('插入数据成功')
2.删
删除权限金山使用,一旦删除,恢复比较麻烦,建议一条一条删除
def delete_data(delete_table):
sql_selete = """delete from {} where id=%d""".format(delete_table)
cur.execute(sql_selete %(1))
conn.commit() # 一定不能忘记commit
cur.close()
conn.close()
print('删除数据成功')
3.改
在外面增加循环可更改任意字段
def update_data(update_table, **kwargs):
sql_selete = """update {} set {}=%s where name=%s""".format(update_table, key) # key、value为kwargs的key与value
cur.execute(sql_selete %(1, value))
conn.commit() # 一定不能忘记commit
cur.close()
conn.close()
print('更新数据成功')
4.查
如果想要增加限制条件那么就需要自己添加where语句
def select_data(select_table):
sql_select = """select * from {}""".format(update_table)
cur.execute(sql_selete)
results = cursor.fetchall() # cursor. fetchall():接收全部的返回结果行。fetchone()、fetchmany(size)与fetchall()的区别自行百度
print(results) # 只是查询结果,如有需要自行解析
cur.close()
conn.close()
python中获取结果注意事项
获取结果其实就是有点像我们之前讲过的光标的问题,我们可以通过获取结果来获取我们所需要的值或者反复获取某些值
1.cursor.fetchone() # 获取结果中的一条数据
2.cursor.fetchall() # 获取结果中的所有数据
3.cursor.fetchmany() # 获取结果中的一些数据,多少我们可以在空格内部制定
4.cursor.scroll(2,mode='relative') # 基于当前位置向后移动然后输出
5.cursor.scroll(0,mode='absoulte') # 给予数据首部向后移动
SQL注入问题
1.我们在登录过程中我们发现只要是名字正确或者他判断为True的时候就会直接登录进去并且还能查到你对应的信息,判断为为True则可以将你的数据库内所有的信息全部取出。
2.发现问题
SQL注入,备注
问题一: select * from 库名 where name='用户名' --注释 'and password=''
问题二: select * from 库名 where name='随便输点东西' or 1=1 --注释'and password=''
3.错乱本质
其实就是由一些特殊含义的符号逃脱了正常的业务逻辑,导致我们后面的代码无法正常运行
4.措施
针对用户输入导致的错误,不需要我们自己处理,我们只需要交给专门的方法自动过滤即可
sql = 'select * from 库名 where name=%s and password=%s'
cuosor.execute(sql,username,password) # 由execute自动帮我们识别出用户所输入的各种数据子哦对那个过滤页数含义符号,最后整合数据执行 一次性提交一个
cursor.executemany() # 一次提交多个
小知识补充
1.as 语法
和python一样都是用来起别名的我们可以使用这个给表起别名,给字段起别名都可以
2.comment 语法
给数据库,表,字段进行备注
3.查看comment的注释
show create table 表名
use information_schema
4.concat、concat_ws 语法 进行字段拼接
concat
concat_wa
5.exists 语法 #如果后方的判断不成功那么就不会执行
select * from userinfo where exists(select * from dapartent where id<100)
视图
1.视图其实就是我们对标进行操作所展现的一种虚拟表我们可以通过生成视图的方法将虚拟表呈现出来,但是我们无法修改内部数据因为他本来就没有存储任何数据,但是我们尽量不要讲视图呈现出来否则就会占用资源。
2.SQL语句
create view as SQL语句; 就可以产生一个我们可以查看的视图
触发器
1.修改运行符号;
我们在使用mysql的时候可能会遇到关键字与执行键冲突的情况,那么我们就肯定遇到这种情况肯定就需要死一个,既然执行程序的符号有特殊含义,为了sql语句的完整性,那么我们就只有改自己的执行键(结束符)。
语法结构:
delimiter 你自己所设置的不与其它关键字冲突的执行键(结束符)
编写我们所需要用到的分号的各种语句
delimiter ; #最后我们需要修改回来
2.触发器
触发器其实就是针对标的增,删,改自动触发的功能(增前,增后,改前,改后,删前,删后)等操作时那么他就会激活并执行。触发器经常用语加强数据的完整性约束和业务规则等。触发器可以从DBA_TRIGGERS,USER_TRIGGERS 数据字典中查到。SQL的触发器是一个能由西永自动执行对数据库修改的语句。
触发器可以查询其他表,而且可以包含负责的SQL语句。他们主要用于强制服从负责的业务规则或要求。触发器也可以用于强制引用完整性,以便再多个表中添加,更新或展出行时,保留在这些表之间所定义的关系,然而,强制引用完整性的最好方法是在相关表中定义主键和外键约束。
语法结构:
create trigger 触发器名称
before/after inser/update/delete
on 表名 for each row
begin
sql语句
end # 结束必须输入end意味着这个触发器的结束
3.触发器案例
# 案例
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
);
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 ; # 结束之后记得再改回来,不然后面结束符就都是$$了
#往表cmd中插入记录,触发触发器,根据IF的条件决定是否插入错误日志
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');
# 查询errlog表记录
select * from errlog;
# 删除触发器
drop trigger tri_after_insert_cmd
事务
-
事务四大特性
- 原子性
- 其实就是讲他的操作视为一个整体,要么都做要么都不做,有一个做不成那么就全都做不能,就像我们的银行卡转账
- 一致性
- 执行结果从一个一致性状态到拎一个一致性状态,因此当前数据库质保函成功事务提交的结果时那么就可以说他保存了一致性
- 隔离性
- 一个事务不被同行的其他事务所干扰
- 持久性
- 一个事务一旦提交那么别的事务就不能为将它改变
- 原子性
-
事务的其他特性
- 事务
- 是数据库中最小的工作单位,是作为单个逻辑工具单元执行一系列操作;这些操作作为一个整体一起向系统提交,要么执行要么不执行,事务是一组不可分割的操作集合
- 脏读
- 其实就是一个事务读取了另一个事务的结果,但是那个事务却回滚了
- 幻读
- 事务第一次读取比第二次读取到的数据少那么就产生了幻读
- 回滚
- 事务提交前将数据库数据恢复到数据修改之前的数据库状态
- 事务
-
隔离级别
-
可重复读
- 保证一个事务,不会修改已经由另一个事务读取但未提交(回滚)的数据,换句话说其实就是在同一个事务中查询都是事务开始时刻一致,重复度,可能会出现“幻读”
-
不可重复读
- 事务A首先读取了一条数据,然后执行逻辑的时候,事务将这条数据改变了,然后事务A再次读取的时候发现数据不匹配了,就是所谓的不可重复读
-
未提交读
- 一个事务一堆数据修改,但没有提交之前,其他并行事务也可以督导,会导致“脏读”,“幻读”,“不可重复读”
- 提交读
- 保证一个事务,不会读到其他并行事务,已修改但未提交的数据,只能读取到已经提交的数据,提交读,可能会出现“幻读”,和“不可重复读”
- 串行化
- 完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞。
-
-
事务关键字
- 事务(transaction)
- 回退(rollbake)
- 提交(commit)
- 保留点(savepoint)
-
事务日志
- 存储引擎在修改表的数据时只需要修改器内存拷贝再把该修改记录到持久在硬盘上的事务日志中,而不用灭磁都修改的数据本身持久到磁盘
- 事务日志采用的是追加方式因此写日志操作是磁盘上一小块区域内的顺序IO而不想随机IO需要穿行于很多地方移动刺头所以采用事务日志的方式相对来说要快的多
- 事务日志持久之后内幕才能中被修改的数据在后台可以慢慢刷回磁盘,目前大多数存储引擎都是这样的,通常被才成为“预写式日志”修改数据需要写两次磁盘
MVCC多版本并发控制
-
MVCC定义
- MVCC简介
- MVCC,全称Multi-Version Concurrency Control,即多版本井发控制,MVCC是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问,在编程语言中实现事务内存。
- MVCC在MysQL InnoDB中的实现主要是为了提高数据库并发性能,用更好的方式去处理读写冲突。做到即使有读写冲突时,也能做到不加锁,非阻塞并发读。
- 当前读
- 像select lock in share mode(共享锁),select forupdate;update,insert,delete(排他锁)这些操作都是一种当前读,为什么叫当前读?就是它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。
- 快照读
- 像不加锁的select操作就是快照读,即不加锁的非阻塞读;快照读的前提是隔离级别不是串行圾别,串行圾别下的快照读会退化成当前读;之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实现是基于多版本并发控制,即MVCC,可以认为MVCC是行锁的一个变种,但它在很多情况下,避免了加锁操作,降低了开销;既然是基于多版本,即快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本。
- 当前读、快照读、MVCC关系
- MVCC多版本并发控制指的是维持一个数据的多个版本,使得读写操作没有冲突,快照读是MySQL为实现MVCC的一个非阻塞读功能。
MVCC模块在MySQL中的具体实现是由 三个隐式字段、undo日志、read view三个组件来实现的。
- MVCC多版本并发控制指的是维持一个数据的多个版本,使得读写操作没有冲突,快照读是MySQL为实现MVCC的一个非阻塞读功能。
- MVCC解决的问题
- 前提数据库并发场景有三种,分别为∶
(1)、读读∶ 不存在任何问题,也不需要并发控制
(2)、读写∶有线程安全问题,可能会造成事务隔离性问题,可能遇到脏读、幻读、不可重复读
(3)、写写∶ 有线程安全问题,可能存在更新丢失问题 - MVCC是一种用来解决读写冲突的无锁并发控制,也就是为事务分配单项增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照。
因此,MVCC可以为数据库解决以下问题∶
(1)、在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能。
(2)、解决脏读、幻读、不可重复读等事务隔离问题,但是不能解决更新丢失问题。
- 前提数据库并发场景有三种,分别为∶
- MVCC简介
-
MVCC注意事项
- MVCC只能在read committed(提交读)、repeatable read(可重复读)两种隔离级别下工作,其他的都不兼容(rad uncommitted:总是读取最新 serializable:所有的行都加锁)
- InnoDB的MVCC通过在每行记录后面保存两个隐藏的列来实现MVCC
- 一个列保存了行的创建时间
- 一个列保存了行的过期时间也可以叫删除时间(本质上是系统版本号)
- 没开是一个新的事务版本号都会自动递增,事务开始时刻的系统版本号会作为事务的版本号来和查询到每行记录版本号进行比较
例如: 刚插入第一条数据的时候,我们的默认事务id为1,实际是这样存储的 | username | create_version | delete_version | | joseph | 1 | | 我们可以看到,我们在content列插入了kobe这条数据,在create_version这列存储了1,1是这次插入操作的事务id然后我们将joseph改为了Alice,实际存储是这样的 | username | create-version | delete_version | | joseph | 1 | 2 | | Alice | 2 | | 还可以看到,update的时候,会先将之前的数据delete_version标记为当前新的事务id,也就是2,然后将新数据写入,将新数据的create_version标记为新的事务id当我们删除数据的时候,实际存储就是这样的 | username | create_version | delete_version | | Alice | 2 | 3 | 最后就是当我们呢查询一条记录的时候,只有满足以下两个条件的记录才会被显示出来: 1.当前是都id要大于或者等于当前行的delete_version值,这表示在事务开始前这行数据已经存在了 2.当前事务id要小于delete_version值,这表示在事务开始之后这行记录才被删除
存储过程
存储过程是一种在数据库中存储复杂程序,以便外部程序调用的一种数据库对象,目的是为了完成特定功能的SQL语句集,经编译创建并保存在数据库中,用户可通过定制存储过程的名字给参数(需要时)来调用执行。
1.与存储过程相关方法
1.1.查看存储过程信息
show create procedure prol;
1.2.查看所有存储过程
show procedure status;
1.3.删除存储过程
drop procedure prol;
2.实例演示
delimiter $$
create proceduer p1(
in m int,
in n int,
out res int
)
bgein
select tname from teacher where tid > m and tid < n;
set res=0;
end $$
delimiter ;
3.针对res需要提前定义
set @res=0; 定义
select @res; 查看
call p1(1,5,@res); 调用
select @res; 查看
内置函数
我们其实可以在mysql中用过help的方式得到该内置函数的使用方法,mysql中的内置使用方法还挺好的说的很详细
1.移除指定字符
Trim、LTrim、RTrim
select '[mobile]',concai('[',trim('molile')']');
2.大小写转换
Lower、Upper
select lower('blue'),lower('blue');
3.获取左右起始指定个数字符
Left、Right
select left('mysql',2)
4.返回读音相似的值(只对英文有效果)
Soundex
首先我们首先需要一张表并且这个表中有名称读音相近的名称
|name|
|json|
|jason|
例如:where Soundex(name)=Soundex('jason')
5.日期格式
date_fromat
在MySQL中表示时间格式尽量采用2022-02-22形式来表示
create table blog(
id int primary key auto_incrment,
name varchar(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_fromat(sub_time) = '2021-1-06' # 返回制定默认值
2.where Year(sub_time)=2021 and Month(sub_time)=07; # 从指定日期值来获取年分值
更多操作
addate 增加一个日期
addtime 增加一个时间
datediff 计算两个日期的差值
流程控制
mysql中的流程控制使用的一般是if、loop、iterate、repeat、while语句来控制流程我们简单地实验几种
1.if条件判断语句
delimiter $$
cerate procedoure proc_if()
begin
declare i int default 0;
if i = 1 then
select 1;
elself i = 2 then
select 2;
else
select 7;
end if;
end $$
delimiter ;
2.while循环,在mysql中只有while循环没有我们的for循环
delimiter $$
cerate procedure proc_while()
begin
declare num int;
set num = 0;
hwile num < 10 do
select
num;
sey num = num + 1;
end while;
end $$
delimiter ;
3.case语句
delimiter $$
case
when i_stall_id = 2 then
set @x1 = @x1 + d_amount;
else
set @x2 = @x2 +d_amount;
end acse
end $$
delimiter ;
索引
- 索引就像是一本书的目录,它能让你更快的找到自己想要的内容。
- 让获取数据变得更有目的性,从而提高数据库检索数据的性能
- 索引在MySQL中也叫做“键”,式存储引擎用于快速找到记录的一种数据结构,我们在mysql中检索一般使用三种检索方式
- primary key
- unique key
- index key
- 上树的三种键在数据查询的时候使用都可以加快查询的速度
- primary key、unique key除了可以加快数据查询还有额外的限制
- index key只能加快数据查询 本身没有任何额外的限制和功能
- 真正理解索引加快数据查询的含义
- 缩印的存在可以加快数据的查询 但是会减慢数据的增删
- 索引的分类
- 普通索引
- 就是sql中最基本的索引类型,允许在定义索引的列中插入重复值和空值
- 唯一索引
- 唯一索引要去索引列的值必须唯一,但允许有空值,如果是组合索引,则值得组合必须唯一,主键索引是一种也特殊的唯一索引,不允许有空值
- 主键索引
- 是一种也输得唯一索引,不逊于有空值,(逐渐约束,是一个主键索引)。一般是在建表的时候同时创建主键索引
- 单列索引
- 单列索引即一个索引只包含单个列,一个表可以有多个单列索引
- 组合索引
- 组合索引就是指在多个自U盾那组合上创建的索引,只有在查询条件中使用了这些字段的左边字段时,索引才会被使用,使用组合索引时遵循最左前缀集合
- 全文索引
- 在定义索引的列上支持值的全文查找,允许这些索引列中插入重复值和空值
- 普通索引
索引底层原理
- 索引的底层其实就是树,树则是一种数据结构,主要用于优化数据查询的操作
- 二叉树:两个分支
- 左边的树的键值小于跟键值,右侧子树的键值大于跟键值
- 二叉平衡树
- 在符合二叉树的条件下,还满足两个子树的高度差最大为1
- B-树(也叫B树)
- 是为了让磁盘等外部内存设计的平衡二叉树
- 红黑树
- 红黑树是一种自平衡二叉树,在平衡二叉树的基础上每个节点又增加了一个颜色的属性,节点的颜色只能是红色或黑色,根节点只能是黑色
- B+树
- B+树是B-树的一种变形,他和B-输的区别差在于有几棵输的节点含有n个关键字
慢查询优化
- 慢查询,顾名思义,就是在日志中记录运行比较慢的SQL语句,是指mysql记录所有执行过long_query_time参数设定的时间阈值的SQL语句查询。
- 慢查询记录在慢查询日志中,通过慢查询日志,可以查找出那些查询语句的执行效率低,以便进行优化。
测试索引
- 首先mysql优化器会判断开销,选择开销最小的查询方式
- 有索引不一定使用索引,当mysql判断where条件没有起到筛选作用时,即使该字段存在索引,也不会使用索引。
- 两个字段同时具有索引修改查询条件两个索引都有效时,选择过滤更多的结果的索引
- 组合索引同理
- 执行顺序→如果有逐渐会优先使用逐渐,其次为唯一索引,再次为组合索引和普通索引。组合索引和普通索引没有先后
联合索引
- 联合索引也叫复合索引,指对表上的两个或两个以上的列字段进行索引。MySQL从左到右使用的索引中的字段,一个查询可以只使用索引中的一部分,但只能是最左侧的部分,仅仅对联合索引后面的任意列执行搜索的时候,该索引是不会有任何作用的