mysql 死锁: 转载:https://www.cnblogs.com/zejin2008/p/5262751.html
所谓死锁<DeadLock>: 是指两个或两个以上的进程在执行过程中,
因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.
此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等竺的进程称为死锁进程.
表级锁不会产生死锁.所以解决死锁主要还是针对于最常用的InnoDB.
死锁的关键在于:两个(或以上)的Session加锁的顺序不一致。
那么对应的解决死锁问题的关键就是:让不同的session加锁有次序
例如两个用户同时投资,A用户金额随机分为2份,分给借款人1,2
B用户金额随机分为2份,分给借款人2,1
由于加锁的顺序不一样,死锁当然很快就出现了。
当对存在的行进行锁的时候(主键),mysql就只有行锁。
当对未存在的行进行锁的时候(即使条件为主键),mysql是会锁住一段范围(有gap锁)
mysql 表锁和行锁: 转载: https://blog.csdn.net/xts5701046/article/details/81395958
1. 多个事务操作同一行数据时,后来的事务处于阻塞等待状态。这样可以避免了脏读等数据一致性的问题。
后来的事务可以操作其他行数据,解决了表锁高并发性能低的问题。
2.问题: 当执行批量修改数据脚本的时候,行锁升级为表锁。其他对订单的操作都处于等待中,
原因:InnoDB只有在通过索引条件检索数据时使用行级锁,否则使用表锁!而模拟操作正是通过id去作为检索条件,
所以通过主键更改数据没问题,因为主键是MySQL自动创建的唯一索引,所以才忽略了行锁变表锁的情况。
处理: 给需要作为查询条件的字段添加索引。用完后可以删掉
总结:InnoDB的行锁是针对索引加的锁,不是针对记录加的锁。并且该索引不能失效,否则都会从行锁升级为表锁。
3. 行锁
表锁的劣势:开销大;加锁慢;会出现死锁
行锁的优势:锁的粒度小,发生锁冲突的概率低;处理并发的能力强
加锁的方式:自动加锁。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁;
对于普通SELECT语句,InnoDB不会加任何锁;当然我们也可以显示的加锁:
共享锁:select * from tableName where … + lock in share more
排他锁:select * from tableName where … + for update
InnoDB和MyISAM的最大不同点有两个:一,InnoDB支持事务(transaction);二,默认采用行级锁。
加锁可以保证事务的一致性,可谓是有人(锁)的地方,就有江湖(事务);
查看当前数据库的事务隔离级别:show variables like ‘tx_isolation’;
间隙锁
当我们用范围条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做”间隙(GAP)”。InnoDB也会对这个”间隙”加锁,这种锁机制就是所谓的间隙锁(Next-Key锁)。
若执行的条件是范围过大,则InnoDB会将整个范围内所有的索引键值全部锁定,很容易对性能造成影响。
排他锁
排他锁,也称写锁,独占锁,当前写操作没有完成前,它会阻断其他写锁和读锁。
共享锁
共享锁,也称读锁,多用于判断数据是否存在,多个读操作可以同时进行而不会互相影响。当如果事务对读锁进行修改操作,很可能会造成死锁。如下图所示。
表锁
表锁的优势:开销小;加锁快;无死锁
表锁的劣势:锁粒度大,发生锁冲突的概率高,并发处理能力低
加锁的方式:自动加锁。查询操作(SELECT),会自动给涉及的所有表加读锁,更新操作(UPDATE、DELETE、INSERT),会自动给涉及的表加写锁。也可以显示加锁:
共享读锁:lock table tableName read;
独占写锁:lock table tableName write;
批量解锁:unlock tables;
什么场景下用表锁
InnoDB默认采用行锁,在未使用索引字段查询时升级为表锁。MySQL这样设计并不是给你挖坑。它有自己的设计目的。
即便你在条件中使用了索引字段,MySQL会根据自身的执行计划,考虑是否使用索引(所以explain命令中会有possible_key 和 key)。如果MySQL认为全表扫描效率更高,它就不会使用索引,这种情况下InnoDB将使用表锁,而不是行锁。因此,在分析锁冲突时,别忘了检查SQL的执行计划,以确认是否真正使用了索引。
第一种情况:全表更新。事务需要更新大部分或全部数据,且表又比较大。若使用行锁,会导致事务执行效率低,从而可能造成其他事务长时间锁等待和更多的锁冲突。
第二种情况:多表查询。事务涉及多个表,比较复杂的关联查询,很可能引起死锁,造成大量事务回滚。这种情况若能一次性锁定事务涉及的表,从而可以避免死锁、减少数据库因事务回滚带来的开销。
mysql的sql语句执行顺序:
一、sql执行顺序 转载至https://www.cnblogs.com/yyjie/p/7788428.html
(1)from
(3) join
(2) on
(4) where
(5)group by(开始使用select中的别名,后面的语句中都可以使用)
(6) avg,sum....
(7)having
(8) select
(9) distinct
(10) order by
第一步:首先对from子句中的前两个表数据加载到内存中去 , 并且执行一个笛卡尔乘积,
此时生成虚拟表 vt1(选择相对小的表做基础表)
第二步:接下来便是应用on筛选器,on 中的逻辑表达式将应用到 vt1 中的各个行,筛选出满足on逻辑表达式的行,
生成虚拟表 vt2
第三步: 如果 from 子句中的表数目多余两个表,那么就将vt3和第三个表连接从而计算笛卡尔乘积,生成虚拟表,
该过程就是一个重复1-3的步骤,最终得到一个新的虚拟表 vt3。
第四步:应用where筛选器,对上一步生产的虚拟表引用where筛选器,生成虚拟表vt4,
第五步:group by 会将vt4切分成若干临时表, 子句将中的唯一的值组合成为一组,得到虚拟表vt5。
第六步:应用having筛选器,生成vt7。having筛选器是第一个也是为唯一一个应用到已分组数据的筛选器。
第七步:处理select子句。将vt7中的在select中出现的列筛选出来。生成vt8.
如果查询sql中有GROUP BY时,会对内存中的若干临时表分别执行SELECT,而且只取各临时表中的第一条记录,
然后再形成新的临时表。这就决定了查询sql使用GROUP BY的场景下,SELECT后面跟的一般是参与分组的字段和
聚合函数,否则查询出的数据要是情况而定。另外聚合函数中的字段可以是表中的任意字段,
需要注意的是聚合函数会自动忽略空值。
第十步:应用distinct子句,vt8中移除相同的行,生成vt9。
第十一步:应用order by子句。按照order_by_condition排序vt9,
第十二步: 执行limit分页
mysql查询语句
技巧: SELECT
检查字段1, COUNT(检查字段1),
检查字段2, COUNT(检查字段2),
...
FROM
table_name
GROUP BY
检查字段1,
检查字段2, ...
HAVING
(COUNT(检查字段1) > 1) AND
(COUNT(检查字段2) > 1) AND
一. mysql DDL语句:
1. 开启服务: services.msc
2. .查看MySQL编码:show variables like '%character%';
3. 增加表字段
ALTER TABLE student ADD COLUMN sex CHAR(10);
4.修改字段排列顺序
ALTER TABLE student MODIFY sname DATE FIRST;
5. information_schema:存储了系统中一些对象信息,如:用户表信息,试图信息,各种数据库变量状态、字符集信息等
mysql:主要是用户的相关权限信息
performance_schema:记录系统性能的数据库。通过performance_schema变更决定是否开启,默认不是开启的
test:测试数据库
6. DDL: 必须加 database; 操作表的话 table ,删除列是 drop 属于修改 都是 alter
7. DDL:操作数据库,和表的列-----------------------------------databases
查看数据库 : show databases
切换数据库: use 数据库名
创建数据库: create database mydb1
删除数据库: drop database mydb1;
修改数据库编码 : alter datebase mydb1 character set utf8 (效对规则)collate utf8_bin;
8. 除了字符串类型需要设置长度其他的都有默认值;
bit(boolean):
float:
int:
decimal : 浮点型,在关于钱的方面使用该类型,不会出现精度确失;
double(5,2) 表示最多5位,其中必须有两位小数,即最大值为999.99;
char(255),固定字符串类型,数据长度不足指定长度,自动补足到指定长度;
varchar(65535) ,可变的字符串类型
date/time/xdatatime和timestamp:一个不传日期,为null,另一个为系统日期;
text(clod): 字符串类型, 可变从小到大都能放
blod :字节类型, 同上;
data 日期类
time 时间类
timestamp: 时间戳类型;
Text: 文本文件
二进制文件: BLOB
9. 查看当前数据库中所有表的名称 show tables;
查看指定表的创建语句: show create table(database) 表名;
查看表结构: desc 表名;
删除表: drop table 表名;
10. 修改表: alter table 表名------------------修改就是alter table 表名 操作
添加列:
alter table 表名 add(
列名,列类型 ,
列名,列类型
);
11. 修改列的类型 alter table 表名 modify 列名 列类型;
修改列名: ................... change 原列名 新列名 类型;
删除列:................... drop 列名;
修改表名称:.................. rename 旧表名 to 新表名
修改表的字符集: character set 字符集;(utf8)
二. DCL:
1.创建用户 create user 用户名@ip地址 identified by '密码';
用户只能在指定的ip地址上登录
create user 用户名@'%' identified by '密码';
用户可以在任意地址登录
2.给用户授权,在主用户中授权
grant 权限1,...,权限n on 数据库.* to 用户名@ip地址
grant all on 数据库.* to 用户名@ip地址;
3.撤销授权
revoke 权限1,..,权限n ON 数据库.from 用户名@ip地址
4.查看权限
show grants for 用户名@ip地址
5.删除用户
drop user 用户名@ip地址
三. DML:
1. ON DUPLICATE KEY UPDATE:在表中存在unique索引或者primary key,
如果插入行后会导致一个unique索引或primary key中出现重复值,则执行旧行udpate操作
insert into emp values('liu','2012-06-08') on duplicate key update sal=sal+3000;
2: 使用IGNORE时,该行仍然未被插入,但是不会出现错误
在日常工作中,ignore主要用于一条insert语句中有多个值,如果有一条语句失败,不会导致别的语句也失败
insert ignore into emp_ignore(ename,depton) values('shan',4),('yang',5);
3. 注意:除非表中存在primary key或unique索引,否则,使用replace语句是没有意义的
replace的功能类似insert。只有一点除外,如果表中一个旧记录与一个用于primary key或
一个unique索引的新记录具有相同的值,则在新记录被插入之前,就记录被删除。
replace into emp set ename='dong',sal=30000,depton=5;
4. DML: 什么都不用加, 插入 insert into , 修改是 update set , 删除是 delete from
5. DML : 对表记录的操作(增删改) ,对表行的操作
6. 修改数据----------------------------------------------------------------update 表名 set
update 表名 set 列名1=值1, 列名2=值2,.....[where 条件]-------------where条件
7. where条件 :
和:
where age>=18 and age <= 80;
18到80之间;
where age between 18 and 80;
或:
where name='速度' or name='手动阀';
是:
在具体哪里进行修改
where name in('张三','李四');
为null:
where name is null , 不能使用等号;
不为null:
where age is not null;
8.删除数据
delete from 表名where 条件-------------------------------------------delete from
9.只用作删除整张表
truncate table 表名: 是DDL语句,无法回滚; 将整个表删除,重新创建一个表
10.事物管理只能作用在DML, 使用delete删除所有记录,可以找回
11.在数据库中所有的类型都要使用单引;
四.DQL:
1. 查询语句书写顺序: select - 聚合函数-from -where -group by - having - order by - limit
查询语句执行顺序: from - where - group by - having - select - order by - limit
2. IN 是 = ANY 的别名,二者相同,但 NOT IN 的别名却不是 <> ANY 而是 <> SOME。
ANY 关键字必须接在一个比较操作符的后面
3. union 对两个结果集进行并集操作,重复数据只显示一次
Union All,对两个结果集进行并集操作,重复数据全部显示
4.
查询人数用 count;
查询分组后的用having;
查询分组的用group by;
查询分页的用limit
不为null的数, finull("列名",0);
查询排序用 order by;asc和desc;
查询 去除重复用 distinct;,在select from中间加
查询不是字符串 not in 是 in
非男 用 <>
不为null is not
模糊查询用like,在where后面加,like可以使用占位符
5. 可以写表达式 :select name,age+10 from user; select name,math+english from user;
6基本查询
select 列名 from 表名 where group by having order by;
7.聚合函数 操作列的-------------------------------sum avg平均值 max min count统计列不为null的记录行数
①count --------------------------统计数的
当需要纵向(统计)是可以使用
②当需要纵向求和的时候使用sum()函数
select sum(列名) from emp;
两个列分别求和: select sum(列1),sum(列2)from emp;
两个加起来求和: select sum(列1+列2)from emp;
③统计所有员工的平均工资: select avg(sal) from emp;
④查找最大的和最小的: select max(列1) ,min(列2) from emp;
8.分组查询-----------------------------------------------------------group by 分组依据 只能在同一张表内;
①查询每个部门的部门编号(在同一张表内)和每个部门的工资和(在不同的表内)
select 部门,sum(工资) from 员工表 group by 部门;
②查询每个部门的部门编号以及每个部门的人数;
select 部门,count(*) from 员工表 group by 部门表;
③查询每个部门的部门编号和每个部门工资大于1500的人数;
select 部门,count(*) from 员工表 where 工资列>1500 group by 部门表;
9. having 子句;
①查询工资和大于9000的部门编号和工资之和;
select deptno,sum(工资) from 员工表 group by部门表 having sum(工资)>9000;
10.limit 方言
用来限定查询结果的起始行,以及总行数;
查询5行记录,其实行从0开始
select * from 表名 limit 0,5;
五: 主键和约束,多表查询
1. 约束和多表查询
删除外键约束: alter table 表名 drop foreign key 外键名;
2.单表约束
主键约束: primary key (唯一非空)
唯一约束: unique ------------------------不能有两个一样的
非空约束:not null
3. auto_increment. 自动增长
4.修改表时删除主键自增长:Sid为主键
ALTER TABLE stu CHANGE sid sid INT;
5.实体的关系总结三种关系:
一对多: 一个客户多个订单
多对多: 学生和课程,多个学生一门课,一个学生多们课;
一对一: 公司和地址
一对多的建表原则:
在多的一方创建一个字段,这个字段作为外键指向一的一方的主键.
多对多的建表原则:
借助第三张表,第三张表中至少需要两个字段分别作为两个外键分别指向两张表的主键
一对一:
唯一外键对应:在一对多的基础上对外键加上唯一约束
主键对应:
6.外键约束就是约束这一列的值必须是另一张表的主键值,
就是约束部门表的id只能在员工编号中取值
①部门表内写
constraint 这一列的名字 foreign key(部门表的id) references 员工表(员工ID);
②.不在表内写
alter table 部门表 add constraint 这一列的名字 foreign key(部门表的ID) references 员工表(员工表id);
alter table 部门表 add foreign key(部门表的ID) references 员工表(员工表id);
③.删除外键约束
alter table 部门表 drop foreign key 外键约束中的这一列的名字
7.多表查询:
①.交叉连接 "一般不用" 获得的是两个表的笛卡尔积.
②内连接: inner join -- inner可以省略
1.显示内连接: select * from A inner join B on 条件;
2.隐式内连接: select * from A,B where 条件;
③.外连接 outer join -- outer可以省略
1.左外连接: left outer join 以左边为基准查的,可以查到左边全部信息
select * from A left outer join B on 条件
2.右外连接: right outer join
select * from A right outer join B on 条件
④.自然连接
natural join是对两张表中字段名和数据类型都相同的字段进行等值连接,并返回符合条件的结果 。
使用自然连接要注意,两个表同名的列不能超过1个。
8.子查询: 一个SQL语句查询的过程依赖与另一个SQL查询语句,可以select嵌套
SELECT c.cname,COUNT(*) FROM customer c,orders o WHERE c.cid = o.cid GROUP BY c.cname;
9.子查询返回单值时可以用比较运算符,而使用ANY或ALL谓词时则必须同时使用比较
运算符,其语义为:
>ANY 大于子查询结果的某个值
>ALL 大于子查询结果中的所有值
<ANY 小于子查询结果中的某个值
<ALL 小于子查询结果中的所有值
>=ANY 大于等于子查询结果中的某个值
>=ALL 大于等于子查询结果中的所有值
<=ANY 小于等于子查询结果中的某个值
<=ALL 小于等于子查询结果中的所有值
=ANY 等于子查询结果中的某个值
=ALL 等于子查询结果中的所有值(通常没有实际意义)
!=(或<>)ANY 不等于子查询结果中的某个值
!=(或<>)ALL 不等于子查询结果中的任何一个值
10. 内查询
select * from 员工表 领导编号, 员工表 员工编码 where 员工表.领导编号=员工表.员工编号
11. natural join:自然连接(不允许带on/using)
natrual join:全自然连接,对左右2个表相同名字的列进行等值匹配,不可用on,using操作指定,自动删除多余重名列
natrual left join:左自然连接,保留2个表的列(删除多余重名列),以左表为准,不存在匹配的右表列,值置为NULL
natrual right join:和左自然连接相反