apache公司 开源共享 免费
mysql [-hlocalhost] -uroot -p 以超级管理员的身份登录
use demo; 查看
-
DCL(数据库控制语言):
-
DDL(数据库定义语言):
-
DML(数据库操纵语言):
-
DQL(数据库查询语言):
-
TCL(事务控制语言):
-
数据库锁:
-
主从配置:
命令行链接方式
mysql -u用户名 -p密码 -h服务器IP地址 -P服务器端口MySQL端口号 -D数据库名
mysql -uroot -p9264934.. -hlocalhost -P3306 -Dguanli
数据库控制语言命令(DCL):
创建本地用户
-- 选择mysql数据库
use mysql;
-- 创建本地用户
create user 'superboy'@'localhost' identified by 'iamsuperboy';
-- 刷新MySQL的系统权限相关表,使添加用户操作生效,以免会出现拒绝访问
flush privileges;
创建远程用户
-- 从192.168.122.12登陆的用户
create user 'superboy'@'192.168.122.12' identified by 'password';
-- 从任意ip登陆的用户
create user 'superboy'@'%' identified by 'password';
-- 不做指定默认为'%'
create user 'superboy' identified by 'password';
对用户的基本操作
创建用户
create user 'wang'@'localhost' identified by 'iamsuperboy';
修改用户的权限:
grant all privileges on *.* to 'wang'@'%';
# all 可以替换为 select,delete,update,create,drop
-- 赋予部分权限,其中的shopping.*表示对以shopping所有文件操作。
grant select,delete,update,insert on 数据库.* to 'wang'@'localhost' identified by
'superboy';
-- 赋予所有权限
grant all privileges on 数据库.* to superboy@localhost identified by 'iamsuperboy';
'revoke'
--撤销权限
revoke privlieges_type on 权限名 from 用户名
删除用户:
Delete FROM mysql.user Where user='user_name' and host='localhost' ;
--允许远程链接
grant all privileges on *.* to 'root'@'%' identified by 'mysql' with grant option;flush privileges;--刷新
修改密码
1、set password for 'wang'@localhost = '123456'
2、update mysql.user set password=password('新密码') where user='root' and host='localhost' flush privileges;
3、mysqladmin -u用户名 -p旧密码 password 新密码
#忘记root密码
1、停掉mysql服务 serve mysql stop
2、cmd中进入安装目录bin 然后 mysqld --console --skip-grant-tables --shared-memory #跳过权限检查
3、再开启另一个cmd进入mysql #直接输入mysql
4、flush privileges
5、退出,并重启系统
数据库备份
mysqldump -u [username] -p[password] [database_name] > [文件夹路径]
mysqldump -uroot -p9264934.. -hlocalhost wangwei > mysql
mysqldump -u [username] -p[password] --no-data [database_name] > [文件夹路径] #只要结构,不要数据
mysqldump -uroot -p9264934.. -hlocalhost --no-data wangwei > mysql
mysqldump -u [username] -p[password] --no-create-info [database_name] > [文件夹路径] #只要数据,不要结构
mysqldump -uroot -p9264934.. -hlocalhost --no-create-info wangwei > mysql
mysqldump -u [username] -p[password] [dbname1,dbname2] > [文件路径] #备份多个数据库
数据库查询
-
数据库查看
- 查看所有的表:show tables
- 查看表的信息: show full tables;
- 查看相关列:show columns from teach;
show columns from teach like 'id';
show columns from teach like '%e%'; #查看带有 ’e‘的内容
-
查看用户信息
查看当前用户:select user();
select current_user();
查看当前有多少用户登录
select user,host,db,command from information_schema.procrsslist:
数据库维护
-
分析表
analyze table 表名1 [表名2]
-
优化表
optimize table 表名
-
检查表
check table 表名
-
修复表
repair table 表名
-
查看表的字段内容
desc t1; //自增 primary key//主键
-
添加数据
insert into t1 values(1,'tom','man',18);
insert into t1 (id,name,sex,age) values(1,'tom','man',18);
-
sql注入
" or 1=1;--
-
查看数据是否添加成功
select * from t1;
-
删除一个表
drop t1;
-
删除表中的一行数据
delete from stu where id=1
-
替换某字段内容的update语句
update t1 set id=replace(id,1,2);
update t1 set sex='woman' where c_id=1;
数据库定义语言(DDL)
新建数据库
create database [if not exists] database_name
删除数据库
drop database [if exists] database_name
创建表
create table ceshi1(
id int(10) not null auto_increment primary key,
name varchar(10),
age varchar(10),
sex enum('男','女') NOT NULL,
phone varchar(11) unique,
habbit set("游泳","健身"),
pasword varchar(32))default charset=utf8; comment='示例';
修改表
alter table 表名 add|drop|modify|change|alter|rename
-
alter 增加列
alter table user add sex enum("男","女") not null [after name]
-
alter 增加在table最后一列 的一个属性
alter table t2 add hobby char(20);
-
alter 在table的第一列添加新字段属性
alter table t2 add project int first;
-
alter 在sex字段之后添加新字段num属性
alter table t2 add num int after sex;
-
alter 删除表中的字段
alter table t2 drop class_id; //删除class_id字段
-
alter 添加主键
alert table t2 primary key(id)
-
alter (设置默认值)
ALTER TABLE student ALTER class_id SET DEFAULT 0;//设置默认值为0
ALTER TABLE student ALTER class_id DROP DEFAULT;//删除默认值
*为什么有了MODIFY和CHANGE还要来个ALTER呢?这是因为另外两个在修改的时候会把字段之前旧的属性全部覆盖掉
举个例子:现在需要修改class_id DEFAULT的值,我们需要这么写
ALTER TABLE student MODIFY class_id VARCHAR(20) DEFAULT 10;
而采用ALTER则不需要则可以只需要设置默认值
-
modify && change (修改字段)
区别:change必须指定新的字段名而modify则不需要
如果需要修改字段名只能用CHANGE,否则用哪个都可以
alter table t1 modify num char(10);
//modify 修改num 的数据类型int(10)=>char(10)
ALTER TABLE t2 CHANGE class_id c_id VARCHAR(20);
//将class_id字段名改为c_id并修改数据类型为VARCHAR(20)
ALTER TABLE t2 CHANGE class_id class_id VARCHAR(20);
//修改class_id数据类型为VARCHAR(20)不修改字段名
ALTER TABLE t2 MODIFY class_id VARCHAR(20);
//将class_id数据类型修改为VARCHAR(20)
-
rename (重命名数据表)
alter table t2 rename to t2s;
修改存储引擎
-
修改引擎
#先删除再添加
alter table t2s engine=myisam; //将存储引擎修改为myisam
-
删除引擎
alter table t2 drop index column_name
-
删除引擎
alter table t2 engine=InnDB
show engines
show create table 表名
-
修改自增值(开始值)
alter table t2 auto_increment = 1
MyISAM
不支持事务,不支持外键,访问速度特别快(主要的基本应用为insert,select),创建成功后,有以下三个文件,扩展名分别为(二进制)
-
.frm(存储表定义,表结构)
-
MYD(MYData存储数据)
-
MYI(MYIndex,存储索引)
InnoDB
-
健壮的事务型存储引擎
-
更新密集的表
-
自动灾难恢复
-
外键约束
-
需要事务支持
索引类型
-
主键索引 primary
-
一个表中唯一的,在数据的查询,写入,读出能够按照一定的顺序,一定排列进行有序的操作,并且除主键外的其他的字段都会收到其影响
-
主键的值只能是唯一的,不能重复,auto_increment
-
-
唯一的键 unique
-
一个表中能够给多个字段设置唯一的键,他会在查询本字段,形成一定的顺序,分组查询
-
在本字段中,不能出现相同的内容,除了NULL外
-
-
普通索引 index
-
能给多个字段设置普通索引,会在查询本字段
-
-
文本索引 fulltext mysql 5.7版本后有效
-
文本编辑器
-
帮助我们在大批文本中有序查找内容
-
外键
-
查看外键
show create table student;
-
创建外键
alter table student
add foreign key(cid)
references classes(cid) on delete cascade;
-
删除外键
alter table student
drop key aa; #删除约束
alter table student
drop foreign key aa; #删除键
1、create table if not exists classes( #创建主表 :班级表
cid int(10) auto_increment primary key,
cnaem varchar(20))default charset=utf8
2、create table if not exists student( #创建副表 :学生表
sid int(10) auto_increment primary key,
snaem varchar(20),
cid int(10),
constraint aa foreign key(cid) references classes(cid) # ******加外键
)default charset=utf8
-
外键链接下,删除主表内容提示
on delete
district(默认) cascade(同时删除) no action(什么都不做) set null(设置为空)
on update
district(默认) cascade(同时删除) no action(什么都不做) set null(设置为空)
create table if not exists student( #没附表的情况下 创建副表
sid int(10) auto_increment primary key,
snaem varchar(20),
cid int(10),
constraint aa foreign key(cid) references classes(cid) on delete cascade
)default charset=utf8
#或
alter table student #有副表没外键的情况下
add foreign key(cid)
references classes(cid) on delete cascade;
数据库操纵语言(DML)
insert
-
插入的内容与原unique的id等唯一值冲突的时候
insert into student (sid,sname,cid) values (3,ai,3) on duplicate key update sid=sid+1 #student 内有sid=3的数据
-
快速复制一个表的结构
create table aaa like stu
-
快速复制一个表的内容
insert into aaa select * from stu
-
replace
可以置换现有的主键或unique
replace into aaa (sname, cid) value("zhangsan",3)
update
update low_priority t1 #low_priority 延迟更新,等没人查询在更新 set column_name1 = expr1 column_name2 = expr2
where
condition
show full tables
-
带有select子句的更新
update stu set sname='111' where id=5;
select tname from teach order by id asc;#随机取 desc倒序
select tname from teach order by rand() limit 1;
#两个表之间的更新
update stu set tname=(select tname from teach order by rand() limit 1) where tname is null;
#关联更新
update table1,table2,...
set table1.attr=val,table2.attr=val,...
where condition
update table1 join table2 on...
set table1.attr=val,table2.attr=val,...
where condition
update classes,student where classes.cname=student.sname set classes.cname="aa",student.sname=""
delete
-
带有limit的删除语句
delete from student order by id desc limit 1 #删除id从后致前的第一个
-
关联删除
delete classes,student from classes,student where classes.cname="allj"
清空数据
delete fro student # 逐条删除,主键自增不会从1开始,而是继续,效率低
truncate [table] student #自增从1开始 效率高
日志管理
记录服务器运行信息,通过日志文件可以监视服务器的运行状态和性能,还能对服务器进行排错与故障处理
-
MySQL有六种不同类型的日志:
-
错误日志:记录启动,运行或停止时出现的问题,一般也记录警告信息 一般开启
-
一般查询日志:记录客户端的链接和执行的语句 一般关闭
-
慢查询日志:记录所有执行时间超过long_time的所有不适用索引的
-
二进制日志:数据库信息有任何改变,都会放到二进制日志中 (需要指定)
-
中继日志:
-
事务日志:
-
-
查询变量
show global variables [like '%log%'] -
修改变量
set global variables_name=val
-
错误日志
-
查看错误日志地址
show global variables like ”log_error" -
警告信息开关
show global variables like "log_warnings"; #查看是否开启 开启为1,关闭为0
set global log_warnings=0 #关闭
-
-
一般查询日志
1. 启用开关:general_log=(ON|OFF) #set global general_log=ON 一般时候都关闭
2. 记录类型:log_output #show global variables like
3. 查看存储位置:general_log_file #show global variables like-
查看错误日志地址
show global variables like ”log_error" 警告信息开关2.2.错误警告开关
show global variables like "log_warnings"; #查看是否开启 开启为1,关闭为0
set global log_warnings=0 #关闭 -
-
慢查询日志
放到配置文件中
查询超时时间: long_query_time=3
查询慢查询 : log_slow_querys={YES|NO}
启动慢查日志: log_query_log=1 (on|off)
日志记录文件: slow_query_log_file[=file_name]
数据库查询语言(DQL)
*
通配符 所有
函数 | 描述 |
---|---|
escape ‘$’ | 把 $ 规定为转义字符 |
cast(1982-3-1 as data) | 把1928-3-1转换成data型 |
count(cname) | cname的条数 |
sqlfind_in_set(needle,place) | needle:查询内容 place:所在字段 |
select
select count(cname) as num from classes
select
column_1 , column_2,...
from a
table_1
-
模糊查询
内容 描述 %老师 以老师结尾的数据 老师% 以老师开头的数据 _老师 老师前面只有一个可变量 老师_ 老师后面只有一个可变量 like 精确查询 = 精确查询 -
where
-
语句顺序
where
conditions
group by column_1
having group_conditions
order by column_
limit offset, length
操作符 描述
= #等于,几乎任何数据类型都可以用
<> != #不等于
<
>
<=
>=
逻辑运算符
or #或者
and #并且
not #非
操作/逻辑运算符 | 描述 |
---|---|
= | 等于 |
<>!= | 不等于 |
< | 小于 |
> | 大于 |
<= | |
>= | |
or | 或 |
not | 非 |
and | 和 |
-
between 包含两端
(cast(1982-3-1 as data) 把1928-3-1转换成data型)
select * from student where birth between cast(1982-3-1 as data) and cast(1988-6-10 as data) ;
-
in
select * from classes where sqlfind_in_set(l,cname) #一个字段中含多个内容
-
group by
select
c1,c2,c3,....
from
table
where
where_conditions
group by t1,t2,t3...;
having
分组后进行筛选 where是分组前筛选
having后可跟条件(函数)
函数 | 描述 |
---|---|
avg() | 计算一组值 |
count() | |
instr() | |
sum() | |
min() | |
max() |
1、通过时间分类 看一时间段内进货 额
2、通过类别
3、时间、类
-
order by
对
单列或多列
的查询结果
进行升序或降序
排序
select column1,column2,...
from t2
order by num desc,price asc #降序排列 asc升序 以前一列为基础,再排后一列
select column1,column2,...
from t2
order by field(name,"商品3","商品2","商品1")desc / asc #自定义排序
-
limit
约束
查询结果
的行数 ,一般跟order by 一起使用
select column1,column2,...
from tablename
limit offset , count #offset:偏移量 count:条数
#只有一个参数n:从头开始取n条
select * from goods where cid=1 group by cid desc limit
关联查询
表与表之间有关系,通过关系去查询
MySQL支持一下连接:
-
交叉链接
select cname,gname
from category cross join goods;
-
内链接
select
name
from
t1
inner join
t2 on t1.id=t2.id
-
左连接
select #以左面为基础
name
from
t1
left join
t2 on t1.id=t2.id
-
右连接
select #以右面为基础
name
from
t1
right join
t2 on t1.id=t2.id
-
联合查询
union #可以去掉重复项 union all 包括重复项
select cname from category union select gname from goods;
子查询
把一个查询嵌套在另一个查询,叫内部查询
-
分类
-
标量子查询:返回但一直的标量,最简单的形式
-
列子查询:返回结果是N行一列
-
行子查询:返回结果为一行N列
-
表子查询:返回结果为N行N列
-
-
标量子查询(一个值)
select * from article where uid = (select uid from user where status=1 order by uid desc limit 1) in
-
关键字
any
all
any :< > = <>条件中的任何一个就可以
all: < > = <> 条件中的所有条件才可以
select * from goods where cid < any (select id from category where id=3 or id=2)
#all
2.列子查询
函数
聚合函数
总值,平均值,最大值,最小值,求和 除count外会忽略null
-
count()
select count(*) from category group by cid; -
avg 平均数
-
num
-
max(),min()
-
group_conatan()
把分组后的结果连接起来
select group_concat(gname) from goods group by cid; -
concat() 字符串链接函数
select concat("first","last") from names
#concat_wg() 指定连接符号
select concat_ws("-","first","last") from names
-
left() 指定从左至右取的内容长度
select left ("abcdef",3)
"abc"
-
replace() 替换,更新
select replace("this is firts","firts","first") #把""中的 firts 换成first
-
substring() 截取 可以从任意位置取
select substring("abcdefg"2,2) #从第二位开始,取两个
-
trim() 删除不必要的前导或尾随字符
select trim({both|leading|trailing} from str)
select trim(" abcd ") #默认去掉前后的空格
select trim(leading from "abcd" ) #之去掉前面的
select trim(leading "a" from "abcd" ) #去掉前面的 a
select trim(both "a" from "abcd" ) #去掉所有的 a
-
format 保留有效数字位数
默认en_US
select format(1001.353535,2) #保留三位
select format(1001.353535,2,"de_DE") #默认en_US 改成 de_DE
时间函数
-
curdate() 返回当前的日期
select curdate()
-
now()
select now()
select now(),sleep(5),now()
-
sysdate()
返回指定日期函数
select sysdate()
select sysdate(),sleep(5),sysdate()
-
day() 获取今天几号
-
month()
select month(now());
-
year()
-
weekday(now()) 获取星期几
-
dayname() 获取星期几英文名称
set @@lc_time_names = 'zh_CN'; #改中文
select dayname(time) from goods;
时间计算函数
-
datediff()
select datediff("2017-08-03","2018-08-03") #相差几天
-
timediff()
select timediff("2017-08-03 12:00:00","2018-08-03 12:00:00") #相差得时间
-
timestampdiff( unit, begin,end)
unit:microsecond second minute hour day week month quarter year
#unit:microsecond,second,minute,hour,day,week,month,quarter,year
select timestampdiff(day,"2017-08-03 12:00:00","2018-08-03 12:00:00") #相差得时间用什 么单位表示
-
date_add(start_date,interval expr unit)
在开始时间上加一个时间后得到的时间
select date_add("2018-12-31 23:59:59",interval "1:1" minute_second)
视图
mysql中有一些复杂的语句,对于复杂的查询,每一次查询都是对性能的消耗,而视图就是把第一次所查询出来的内容做成一个表
-
查看所有视图
show full view
-
查看视图创建过程
show create view viewname
-
创建视图
create view viewname as select ...
-
修改视图
alter view viewname as select ...
-
创建或替换视图
没有就创建,有就修改
creat or replace view viewname as select ... #viewname:视图名
-
删除视图
drop view [databases.name].[viewname]
临时表
使用频率低,不想每一次都查询,又不想创建视图,临时保存数据,生命周期为数据库使用期间,自动删除
-
创建
create temporary table tempname select ... #没有as tempname:临时表表名
事务
只有InnoDB支持事务
数据库处理操作,执行就好像它是一个单一的一组有序的工作单元,在组内每个单独的操作是成功的,那么一个事务才是完整的,如果事务中任何操作失败,整个事务将失败。
事务性质
-
原子性:确保了工作单位中的所有操作都成功完成:否则,事务被终止,在失败时会被回滚到事务操作以前的状态。
-
一致性:可确保数据库在正确的更改状态在一个成功的结果提交事务。
-
隔离:使事务相互独立地操作。
-
持久性:确保了提交事务的结果或系统故障情况下仍然存在作用。
事务控制语句
-
BEGIN或START TRANSACTION;显示地开启一个事务;
-
COMMIT;也可以使用COMMIT WORK,不过二者是等价的。COMMIT会提交事务,并使已对数据库进行的所有修改成为永久性的
-
ROLLBACK;有可以使用ROLLBACK WORK,不过二者是等价的。回滚会结束用户的事务,并撤销正在进行的所有未提交的修改
-
SET AUTOCOMMIT=0 禁止自动提交
-
SET AUTOCOMMIT=1 开启自动提交 variable
锁
不同的存储引擎支持不同的锁机制 mysql中锁的大分类分为:1、表级锁,2、行级锁,3、页面锁
-
表级锁:开销小,加锁快,不会出现死锁,锁定粒度大,发生锁冲突的概率最高,并发度最低
-
行级锁:开销大,加锁慢,会出现死锁,锁定粒度小,发生锁冲突的概率低,并发度高。
表级锁
共享锁:读锁,所有人(包括自己)能查看,不能修改(修改会提示错误),锁期间不能操作别的表
独占锁:写锁,只有 自己可见可修改,锁期间不能操作别的表
-
mysql表级锁存储引擎:
-
MyISAM 引擎
-
MEMORY 引擎
-
-
加锁(用到MySQL时候,MySQL本身已经给加锁了)
演示事务操作的时候 操作多条命令时,不希望被其他用户修改
lock tables t1 [t2] read [local], lock tables t1 [t2] write [local]
-
释放锁
unlock tables;
-
查看表锁征用情况:
-
table_locks_immediate
-
table_locks_waited
show status like "table%"
show status like "%lock%"
show processlist #查看那些当前是哪些命令在等待,从而进行优化
show open tables #当前倍速欧珠的表以及锁的次数 -
-
表锁优化
-
optimize table 表名
-
set concurrent_insert=2 允许并发插入
-
是否设置写的优先级,(登录)
-
是否设置写内存,解决批量插入数据(新闻系统更新)
-
解决并发问题
-
并发插入(只能插入,不能修改和删除)
MyISAM存储引擎有一个系统变量 concurrent_insert ,专门控制并发插入行为 值可为 0,1,2
-
cuncurrent_insert 为0时:不允许并发插入
-
cuncurrent_insert 为1:如果MyISAM没有空洞:即使有锁,也会从尾部插入 有空洞:不插入 (空洞:id=1,2,4 少3)
-
cuncurrent_insert 为2:加锁的时候把 [local] 加上 allways 总是可以队尾插入信息(锁的情况下)
********很重要,用mysql就改成2
set cuncurrent_insert=2
-
-
-
读写锁的优先级
-
修改写锁的最大次数
set global max_write_lock_count=1 #写一次之后暂停写操作,给读操作机会-
降低写锁的优先级
set global low_priority_updates=1 -
-
设置写内存
可以根据具体的业务设置读写内存
max_allowed_packet=1M # 限制接受的数据包大小,大的插入和更新会被简直掉
net_buffer_length=2k #insert 语句的缓存值 (),(),() 2k-16M
bulk_insert_buffer_size=8M #一次性insert语句插入的大小
间隙锁
数据库里id有 1,3,4,5 锁是id>1 再操作id=2的时候也会被锁。所以确定条件的时候一定要有范围
行级锁
引擎:InnoDB
如果一个事务请求的锁模式与当前的锁兼容,InnoDB就将请求的锁授予该事务;反之如果两者不兼容,该事务就要等待锁释放
-
请求锁是否兼容当前锁模式
X(排他锁) | IX(意向排他锁) | S(共享锁) | IS(意向共享锁) | |
---|---|---|---|---|
X | 冲突 | 冲突 | 冲突 | 冲突 |
IX | 冲突 | 兼容 | 冲突 | 兼容 |
S | 冲突 | 冲突 | 兼容 | 兼容 |
IS | 冲突 | 兼容 | 兼容 | 兼容 |
-
特点
-
想让InnoDB 上行锁,当前行的操作字段必须要有索引。
-
如果操作行的操作字段没有索引,行锁会自动升级为表锁。
-
即使有索引,但用字段的时候修改了类型,索引失效 eg:(规定类型:name varchar(255) 命令输入:name=0;)
-
意向锁是InnoDB自己加的,不用干预;对于update,delete和insert,InnoDB会自动加排他锁(X);对于select不会自动加共享锁(S)。
-
当对一行上了排他锁(update,delete,insert),其他用户对这一行数据没有任何权限,但并不影响其他用户修改其他数据。
-
当对一行上了排他锁(update,delete,insert)后,其他用户可以对当前行进行读操作:修改前的值(InnoDB默认隔离方式)。
-
研究行锁时,需要将自动提交关闭,
set autocommit = 0
#注:如果有多个客户端,每个都要设置
-
-
加锁
共享锁:select 后需要加 lock in share mode
排他锁:select 后需要加 for update -
释放锁
commit;
rollback; -
查询行锁征用
show status like 'innodb_row_lock%';
-
隔离
-
查看隔离级别
select @@session.tx_isolation
-
设置隔离级别
set session transaction isolation level read uncommitted(读未提交) #脏读
#read committed(不可重复度)
#read (可重复读)
#read用到mvcc技术(多版本并发控制)Multiversion Currency control
-
隔离级别
-
可读取未确认(Read uncommitted)
写事务阻止其他写事务,避免了更新遗失。但是没有阻止其他读事务。
存在的问题:脏读。即读取到不正确的数据,因为另一个事务可能还没提交最终数据,这个读事务就读取了中途的数据,这个数据可能是不正确的。
解决办法就是下面的“可读取确认”。
-
可读取确认(Read committed)
写事务会阻止其他读写事务。读事务不会阻止其他任何事务。
大部分数据库使用的默认隔离级别,兼顾速度和正确性。
存在的问题:不可重复读。即在一次事务之间,进行了两次读取,但是结果不一样,可能第一次id为1的人叫“李三”,第二次读id为1的人就叫了“李四”。因为读取操作不会阻止其他事务。
解决办法就是下面的“可重复读”。
-
可重复读(Repeatable read)
读事务会阻止其他写事务,但是不会阻止其他读事务。
存在的问题:幻读。可重复读阻止的写事务包括update和delete(只给存在的表加上了锁),但是不包括insert(新行不存在,所以没有办法加锁),所以一个事务第一次读取可能读取到了10条记录,但是第二次可能读取到11条,这就是幻读。
解决办法就是下面的“串行化”。
-
可串行化(Serializable)
读加共享锁,写加排他锁。这样读取事务可以并发,但是读写,写写事务之间都是互斥的,基本上就是一个个执行事务,所以叫串行化。
-
-
脏读:
事务A修改了一个数据,但未提交,事务B读到了事务A未提交的更新结果,如果事务A提交失败,事务B读到的就是脏数据。
-
不可重复读:
在同一个事务中,对于同一份数据读取到的结果不一致。比如,事务B在事务A提交前读到的结果,和提交后读到的结果可能不同。
-
幻读:
在同一个事务中,同一个查询多次返回的结果不一致。通常是因为在事务A中进行了一次全局操作,如新增了一条记录;事务B在事务A提交前后各执行了一次查询操作,发现后一次比前一次多了一条记录。
-
优化行级锁
1、精心设计索引,尽量使用索引访问数据
2、选择合理的事务,小事务发生锁冲突的几率小
3、给记录集手动加锁,最好一次性请求足够级别的锁(写锁级别>读锁级别),不要先申请共享再申请排他。
4、尽量用相等的条件访问数据,这样可以避免间隙锁对并发插入的影响
5、对于一些特定事务,可以使用表锁来提高处理速度或减少死锁的可能。(购物,三表同时修改 库存,销售记录,购 物车)
-
练习
课程表 id 课程名 老师id
老师表 id 姓名 简介id
简介表 id 信息
查看 带python老师的信息 3种
1、select iname from info where id=(select iid from teacher where id=(select tid from class where cid=1));
2、 SELECT iname FROM info,class,teacher where info.id=teacher.iid and class.tid=teacher.id and class.cid=1;
3、 select iname FROM info INNER join teacher on info.id=teacher.iid INNER JOIN class on teacher.id=class.tid where class.cid=1;
4、select iname from info join teacher on info.id=teacher.iid where teacher.id=(select tid from class where cid=1);
-
explain+语句 测速率 分析语句合理性
主从复制
实际生产中,有单台MySQL数据库是完全不满足实际需求,无论安全性,高可用性以及高并发性等各方面要求。而主从mysql会实现mysql的实时备份,高可用,读写分离场景。
-
原理
-
配置过程
-
两台服务器
-
双方mysql版本一致,如果不一致,从结点高于主节点
-
服务器防火墙要关闭掉
sudo ufw status
ubuntu系统
-
上方数据库用户需要具有远程访问的权限
-
-
修改主服务器的MySQL的配置文件 window
放到(my.ini)的mysqld下面
linux(my.cnf)
#mysql 唯一id
server-id=1
#二进制文件,此项为必填项,否则不能同步数据 (可以加路径)
log-bin="mysql-bin"
#指定二进制错误文件所放的位置
log-error="mysql-error"
#需同步的数据库 如果需要同步多个
binlog-do-db=wangwei
#binlog-do-db="表名"
#不需要同步的数据库
binlog-ignore=mysql
read_only #只读 -
给从数据库授权(可以从主服务器取数据)
grant replication slave on *.* to 'root'@'192.168.2.155' identified by '9264934.。' flush privileges;
-
重启服务器(数据库服务)
service mysqld restart #
-
查看主服务器状态
show master status; -
从服务器配置
1.修改从服务器的mysql配置文件,注意ID没有被别的mysql服务占用
server-id = 2
log-bin = "mysql-bin"
replicate-do-db =wangwei
replicate-ignore-db = mysql2.重启mysql服务
3.执行同步sql语句
change master to master_host='192.168.217.135', #设置要连接的主服务器IP地址master_user='root', #设置要连接的主服务器用户名 master_password='123456', #设置要连接的主服务器密码 master_log_file='mysql-bin.000002', #设置要连接的主服务器bin日志的日志名称 master_log_pos=1041; #设置要连接的主服务器bin日志的记录位置 change master to master_host = '192.168.217.135', master_user = 'root', master_password = '123456', master_log_file = 'mysql-bin.000008', master_log_pos = 107;
4.启动slave同步进程
start slave
#查看状态
show slave status\G # 查看同步状态
#其中Slave_IO_Running Slave_SQL_Running值都是YES,表示状态正常
#如果之前从服务器启动过需要先停止在运行
stop slave -
查看二进制信息
show binary logs; #二进制文件
show master logs; #当前使用的
-
删除二进制文件
purge binary logs to "mysql-bin.000002"; #删除此文件之前的文件-
自动清理
show variable like "expire_logs_day"
set expire_logs_day=7 #7天自动清理一次 -
优化
-
表级优化(锁)
-
系统优化
-
主从复制
-
负载均衡
-
读写分离
-
多表查询,小表在前,大表在后 (where 小表 .x = 大表.y)
left join 给左边的表加索引,right 给右边的表加索引
-
explain
-
id:
-
相同时,由上至下
-
不同时,从大到小
-
-
查询语句
select * fgroup by
distanc+-1
-
派生表
在查询内容再查询
select aa..cname from (select cname,tid from class) as aa; -
type
从表中找到自己想要的数据的方式
ALL<index<range<ref<eq_ref<const<system<NULL
ALL:遍历全表找到匹配的行,并且查找的内容不带索引
index:只遍历索引树,查找索引的列 #加索引
range: 检索给定的范围,查找的内容不带索引,选择的行带索引 #id<10 尽量不用in in会破坏掉索引
ref:确定的一个值 #where name="zhangsan"
eq_ref:类似ref,区别就在于使用的是唯一索引 unique
const:主键关联,主键查询
system: -
key_len
索引所占的内存空间 utf8 英文占3字节 中文占4字节
-
Extra
额外信息:
1、Using:temporary: 需要额外的内存存储信息 2、Impossible whe:条件有问题 3、Using filesort: 多次排序,没有索引
复合索引:最佳左前缀;
筛选需优化的内容
用慢查询日志筛选 自己指定一个时间,超出long_time的语句会存到慢查询的日志中,然后在日志中找到那条语句用explain检测。
优化索引
可以把要查找的内容加上索引来补救
-
不能将索引作为表达式的一部分,也不能作为参数,否则索引失效
explain select * from class where id+1=1
explain select tname from teacher where left(tname,3)=""; #没有索引 -
索引不能做类型转化
explain select iid from teacher where tname=111 #tname varchar() "1111" -
符合索引遵循左前缀策略
-
索引不能跟or 否则全部失效;
-
复合索引不能有不等号 <> != 或者is null
-
不能用in 可以用between
-
及时删除不用的索引
-
like 查询时尽量不要出现左边的“%”
explain select iid from teacher where tname like "%xx";
其他优化
-
把NULL改成NOT NULL
-
根据业务,尽可能选择小的存储数据类型
-
unsigned 表示不允许复制 -127~128 = 0~255
-
timestamp(时间戳) 使用4个字节, 而 datetime 使用8个字节
-
基本没有使用enum(枚举)
-
尽量少列 不大于10列
-
应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。
-
应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如: select id from t where num is null 可以在num上设置默认值0,确保表中num列没有null值,然后这样查询: select id from t where num=0
-
很多时候用 exists 代替 in 是一个好的选择
-
用Where子句替换HAVING 子句 因为HAVING 只会在检索出所有记录之后才对结果集进行过滤