MySQL官方文档对于锁描述的很清楚,我在这里只补充一些当时有些疑惑或者其他地方补充的知识点或者之类的。
MySQL官方文档:锁
当事务想要加锁时,先生成一个锁结构,如果能够成功获取到锁,那么is_waiting就是false
。
我们知道,当前读会有脏读的问题,即在一个事务运行期间,两次读取可能得到不一样的数据。在innodb中采用了MVCC的方式解决,但是,在某些特殊场景,比如银行,在用户进行存款时需要读取到实时数据,且读取后就不该允许其他事务进行写入了,否则可能导致余额最终结果不符合一致性要求。那么MVCC就无法满足要求了。
因为MVCC采用读视图,属于快照读(一致性读),而快照读无法读取到正在运行中的事务修改的数据。
那么此时,就需要指定用当前读的方式读取数据,为了解决脏读,就需要采用加锁的方式了。加了锁,就可以禁止其他事务写入,也就解决了脏读。
实际上就是读写锁
读锁:select ... lock in share mode;
写锁:select ... for update;
意向锁是表级锁,指示事务稍后需要对表中的行使用哪种类型的锁(共享锁或排他锁)
意向锁不会阻塞除全表请求(例如LOCK TABLES … WRITE)之外的任何内容(如下图兼容关系)。意向锁的主要目的是表明某人正在锁定表中的某一行,或者将要锁定表中的某一行。
行锁实际是索引记录锁,即加在索引上而不是加在记录上,同样的,所谓next-key
等锁实际对象都是索引。
记录锁始终锁定索引记录,即使表未定义索引也是如此。对于此类情况, InnoDB请创建一个隐藏的聚簇索引并使用此索引进行记录锁定
对于使用唯一索引锁定行以搜索唯一行的语句,不需要间隙锁定。这是因为唯一索引能够直接定位到具体的行,从而避免了锁定范围中的其他行或间隙。然而,有一种情况例外,即当搜索条件仅包含多列唯一索引的某些列时,间隙锁定会发生。
(注意不是表锁里的意向锁)
这是一种在行插入之前设置的间隙锁
在MySQL官方文档中,有这么一段话,当时不是很理解
这里做出解释:
具体来说,插入意向锁就是一种解决在多事务环境下处理插入操作而避免阻塞的机制。只要不在同一个位置(即同一条索引)插入,那么就不阻塞其它事务获取插入意向锁和独占锁
插入意向锁的定义:插入意向锁是一种特殊的间隙锁,在事务尝试在某个位置插入行之前设置。这种锁发出一个信号,表明该事务有插入数据的意图,但并不阻止其他事务在不同位置进行插入操作。
多事务插入示例:
插入意向锁的作用:
独占锁的获取:
MySQL官网写了,直接看官网
用于联合索引。
如查询条件:比如a>1 and b=2,其中(a,b)是联合索引。
只用到单个字段的时候,如果没有索引下推,会导致MySQL在找到每一个a>1的记录时都会进行一次回表。
而在MySQL5.6出现索引下推机制后,因为a是范围查询,所以b用不到联合查询索引,innodb直接就在索引中判断剩下的字段是否符合b=2,不会返回server再去主键索引中判断。
所以,使用了索引下推后,虽然 b 列无法使用到联合索引,但是因为它包含在联合索引(a,b)里,所以直接在存储引擎过滤出满足 b=2 的记录后,才去执行回表操作获取整个记录。相比于没有使用索引下推,节省了很多回表操作。
无论删除主键还是创建主键都会对整个表进行重建,所有的二级索引都依赖于主键
对于单字段查询,distinct对单字段进行去重
select distinct name from stu;
对于多字段,distinct对多字段组合结果进行去重,即所有字段相同才被认为是重复的
select distinct name,id from stu;
select distinct (name),id from stu;# 尽管这样写,也是当name和id有关记录都相同时才被认为是重复记录
另外,distinct只能放在第一个查询字段前,否则会报错。因为多字段去重,是所有字段都相同才被认为重复
查找出每个部门中薪资最高的员工。按 任意顺序 返回结果表。
这里注意的是,第一个select中的where字句,使用括号:(departmentId,Employee.salary)可以把两个字段作为一个组合成为筛选条件
# 子查询
select Department.name as Department, Employee.name as Employee, Employee.salary as Salary
from Employee,Department where (departmentId,Employee.salary)
#(departmentId和salary作为一个条件)
in (select departmentId, max(Salary) from Employee group by departmentId)
and Employee.departmentId=Department.id;
# 左外连接 子查询
-- select Department.name as Department,Employee.name as Employee,Salary
-- from Employee
-- left join Department on Employee.DepartmentId = Department.Id
-- where (departmentId, Salary) in
-- (select departmentId, max(Salary) from Employee group by DepartmentId);
avg的参数如果是bool值时,则得到的结果就会转换为0,1。那么可以通过avg函数求概率,1或者0的数量就是所需查找的列的概率。
avg(Status!='completed')
当status不为completed时,为true,则为1。那么1的数量除以总的数据数量就是status不为complete的概率
编写解决方案,找出与之前(昨天的)日期相比温度更高的所有日期的 id 。
这里主要注意日期函数的用法
SELECT b.Id
FROM Weather as a,Weather as b
WHERE a.Temperature < b.Temperature and DATEDIFF(a.RecordDate,b.RecordDate) = -1;
-- SELECT w2.id
-- FROM Weather w1, Weather w2
-- WHERE w2.recordDate = ADDDATE( w1.recordDate, INTERVAL 1 DAY )
-- AND w2.temperature > w1.temperature
#adddate用法可以看看这篇文章https://www.cnblogs.com/jpfss/p/11131540.html
# 子查询
delete from Person where id not in (
select a.id from (# 不能只使用下面的那个select
select min(id) as id from Person group by email
) as a
)
或者使用自连接的方式
# 自连接
DELETE p1
FROM Person p1 JOIN Person p2
ON
p1.Email = p2.Email
AND
p1.Id > p2.Id
JOIN
如果有多个JOIN,后面的JOIN依赖于前面的JOIN结果集进行筛选
LIKE 和 REGEXP的区别
LIKE指定后面跟的表达式是通配符匹配,而不是直接相等匹配,就算记录中存在于LIKE后面的表达式完全相等的列,也不会返回任何东西。如
products表
查询:
where 和 having的区别
where作用于一行记录,作用于group by之前,筛选出符合条件的记录。
而having作用于group by之后,作用于分组后的结果,筛选出符合条件的组