北京网站建设流程,包装网站建设价格,企业邮箱域名,网络运维周报概述 定义#xff1a; 锁是计算机协调多个进程或者线程并发访问某一资源的机制 在数据库中#xff0c;除传统的计算资源#xff08;如CPU,RAM,IO等#xff09;的争用以外#xff0c;数据也是一种供许多用户共享的资源。如何保证数据并发 访问的一致性、有效性是所有数据库…概述 定义 锁是计算机协调多个进程或者线程并发访问某一资源的机制 在数据库中除传统的计算资源如CPU,RAM,IO等的争用以外数据也是一种供许多用户共享的资源。如何保证数据并发 访问的一致性、有效性是所有数据库必须解决的一个问题锁冲突也是影响数据库并发访问性能的一个重要因素。从这个角度 来说锁对数据库而言显得尤其重要也更加复杂。 实际场景案例生活购物 打个比方我们在淘宝上抢购一件商品商品只有一件库存这个时候如果有很多人想去买那么如何解决是你买到还是其他人买到的问题 这里肯定要用到事务我们先从库存表中取出物品数量然后插入订单付款后插入付款记录表 然后更新商品数量。在这个过程中使用锁可以对有限资源进行保护解决隔离和并发的矛盾 锁分类 从数据操作的类型读、写分 读锁共享锁针对同一份数据多个读操作可以同时进行而不会互相影响 写锁排它锁当前写操作没有完成前它会阻断其他写锁和读锁。 从对数据操作的颗粒度:表锁行锁 三锁 开销、加锁速度、死锁、粒度、并发性能。只能就具体应用的特点来说哪种锁更合适 表锁偏读 特点 偏向MyISAM存储引擎开销小加锁快无死锁锁定粒度大发生锁冲突的概率最高并发最低 案例分析 建表SQL 加读锁 加写锁 【表级锁分析-建表sql】
create table mylock(
id int not null primary key auto_increment,
name varchar(20)
)engine myisam;insert into mylock(name) values(a);
insert into mylock(name) values(b);
insert into mylock(name) values(c);
insert into mylock(name) values(d);
insert into mylock(name) values(e);select * from mylock;【手动添加表锁】
lock table 表名 read(write),表名2 read(write),其他;
lock table mylock read,book write;【查看已添加过的锁】
show open tables;【释放表锁】
unlock tables;加读锁
1.session1 获得表mylock的read锁定 , lock table mylock read;session2连接终端2.session1 可以查询该表的记录select * from mylock;
--当前session1不能查询其他没有锁定的表select * from book;session2等其他终端也可以查询该表的记录
--其他session可以查询或者更新未锁定的表select * from book; update book set card51 where book_id1;3. 当前session中插入或者更新 锁定的表 都会提示错误 insert into mylock(name) values(ee); update mylock set namea1 where id1; 其他session插入或者更新锁定的表会一直等待直到获得锁 insert into mylock(name) values(ee); update mylock set namea1 where id1; 4.释放锁后其他session获得锁对应插入或者更新操作完成。加写锁
我们为mylock表加写锁myISAM存储引擎的写阻塞读的例子1. session1 获得表的write锁定unlock tables; lock tables mylock write;待session1开启写锁后session2在连接终端2.当前session 对锁定的表 查询 更新 插入操作都可以执行select * from mylock where id1; update mylock set namea11 where id1; insert into mylock(name) values(ff);
其他session对锁定表的查询被阻塞需要等待锁被释放 select * from mylock where id1;更新与插入操作会等待释放锁。update mylock set namea11 where id1; insert into mylock(name) values(ff);
备注可以尝试用不同的id进行测试mysql是有缓存的第二次的条件会从缓存中取得影响锁效果的演示3.释放锁 unlock tables;
其他session获得锁返回查询结果############################案例结论######################
myISAM 在执行查询语句select前会自动给涉及的所有表加读锁在执行增删改操作前会自动给涉及的表加写锁。mysql的表级锁有两种模式表共享读锁Table read lock表独占写锁 ( Table write lock )
对比
锁类型 可否兼容 读锁 写锁
读锁 是 是 否
写锁 是 否 否结论
结合上述对比,所以对myISAM表进行操作会有以下情况
1.对MyISAM表的读操作加读锁不会阻塞其他进程对同一张表的读请求但是会阻塞对同一张表的写请求。只有当读锁被释放后才会执行其他进程的写操作。
2.对myISAM表的写操作加写锁会阻塞其他进程对同一张表的读和写操作只有当写操作释放后才会执行其他进程的读写操作简而言之就是读锁会阻塞写但是不会阻塞读而写锁则会把读和写都阻塞。###########################表锁分析####################
【看看那些表被加锁了】
show open tables;【如何分析表锁定】
可以通过检查table_locks_waited 和table_locks_immediate状态变量来分析系统上的表锁定
show status like table%;这里有两个状态变量记录mysql内部表锁定的情况两个变量说明如下
table_locks_waited产生表级锁定的次数表示可以立即获取的查询次数每立即获取锁值加1
table_locks_immediate出现表级锁定争用而发生等待的次数不能立即获取锁的次数每等待一次锁值加1此值高则说明存在着比较严重的表级锁争用的情况此外myisam的读写锁调度是写优先这也是mysiam不适合做写为主表的引擎。因为写锁后其他线程不能做任何
操作大量的更新会使查询很难得到锁从而造成永久阻塞 行锁偏写 特点 偏向InnoDB存储引擎开销大加锁慢会出现死锁锁定粒度最小发生锁冲突的概率最低并发度也最高。 InnoDB与MyISAM的最大不同有两点一是支持事务TRANSACTION;二是采用了行级锁 由于行锁支持事务复习老知识 事务Transation及其ACID属性 事务transation 及其ACID属性 事务是由一组sql组成的逻辑处理单元事务具有以下四个属性通常简称事务的ACID属性。 原子性Atomicity: 事务是一个原子操作单元其对数据的修改要么全部执行要么全部不执行。 一致性Consistent:在事务开始和完成时数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改以保持数据的完整性事务结束时所有的内部数据结构如B树索引或者双向链表也都是必须是正确的。 隔离性Isolation:数据库系统提供一定的隔离机制保证事务在不受外部并发操作影响的‘独立’环境执行。这就意味着事务处理过程的中间状态对外部是不可见的反之亦然。 持久性Durable:事务完成后它对数据的修改是永久性的即使出现系统故障也能够保持。 并发事务处理带来的问题 更新丢失lost update 当两个或者多个事务选择同一行然后基于最初选定的值更新该行时由于每个事务都不知道其他事务的存在隔离性就会发生丢失更新问题 -----最后的更新覆盖了由其他事务所做的更新。 例如两个程序员在修改同一个java文件每个程序员独立的更改自己的副本然后保存更改后的副本这样就覆盖了原始文档。最后保存其 更改副本的编辑人员覆盖了前一个程序员所做的更改。 脏读Dirty reads 一个事务正在对一条记录做修改在这个事务完成并提交前这条记录的数据就处于不一致的状态这时候另一个事务也来读取同一条记录 这时候如果不加以控制第二个事务读取了这些‘脏数据’并据此做了进一步的处理就会产生未提交的数据依赖关系。这种现象被形象的叫做‘脏读’ 总结事务A读取到了事务B已修改但是未提交的数据并在这个数据的基础上做了操作。此时如果事务B进行了回滚A读取的数据就无效违反了一致性的要求 不可重复读Non-Repeatable Reads一个事务在读取某些数据后的某个时间再次读取以前读过的数据却发现其读出的数据已经发生了改变、或者某些记录已经被删除了。这种现象叫做‘不可重复读’。 总结事务A读取到了事务B已经提交的修改数据不符合隔离性。 幻读Phantom reads 一个事务按相同的查询条件重新读取以前检索过的数据却发现其他事务插入了满足其查询条件的新数据这种现象就被称为‘幻读’ 总结事务A读取到了事务B提交的新增数据不符合隔离性 注意幻读和脏读有点类似 脏读是事务B里面修改了数据 幻读是事务B里面新增了数据 事务隔离级别 事务隔离级别脏读不可重复读幻读读未提交read-uncommitted是是是不可重复读read-committed否是是可重复读repeatable-read否否是串行化serializable否否否总结数据库的事务隔离越严格并发副作用就越小但是付出的代价也就越大因为事务隔离实质上就是使事务在一定程度上“串行化”进行 这显然与“并发”是矛盾的。同时不同的应用对数据读一致性和事务隔离程度的要求也是不同的。比如许多应用对“不可重复读”和“幻读” 并不敏感可能更关心数据并发访问的能力。 查看当前数据库的事务隔离级别:show variables like tx_isolation; ######################建表SQL##################
create table test_innodb_lock(a int(11),b varchar(16)) engineinnodb;insert into test_innodb_lock values(1,aaa);
insert into test_innodb_lock values(2,222);
insert into test_innodb_lock values(3,3333);
insert into test_innodb_lock values(4,4000);
insert into test_innodb_lock values(5,5000);
insert into test_innodb_lock values(6,6000);
insert into test_innodb_lock values(7,7000);
insert into test_innodb_lock values(8,8000);
insert into test_innodb_lock values(9,9000);
insert into test_innodb_lock values(1,b1);create index test_innodb_lock_a on test_innodb_lock(a);
create index test_innodb_lock_b on test_innodb_lock(b);select * from test_innodb_lock;
######################行锁定基本演示##################行锁定基本演示
1.session1 - set autocommit0;session2 -set autocommit0;2.session1 - update test_innodb_lock set bb1 where a1; #更新但是不提交没有手写commitsession2 - update test_innodb_lock set bb2 where a1; #session2 被阻塞只能等待3. session1 - commit; #提交更新 session2 - 接触阻塞更新正常进行
4. session2 执行命令commit;注意若果session1更新会话a1,session2更新会话a9,互相并不影响。
######################无索引行锁升级为表锁##################
varchar 不用 导致系统自动转换类型, 行锁变表锁
session1 - update test_innodb_lock set a41 where b4000;session2 - update test_innodb_lock set b9000 where a9;
######################间隙锁危害##################
间隙锁的危害
案例间隙锁带来的插入问题
1.session1 - update test_innodb_lock set ba*20 where a 1 and a 5;session2 -insert into test_innodb_lock values(2,200); #阻塞产生暂时不能插入
2.session1 - commit;session2 - 阻塞解除完成插入【什么是间隙锁】
当我们用范围条件而不是相等条件检索数据并请求共享或排它锁时候innoDB会给符合条件的已有数据记录的索引项加锁
对于键值在条件范围内但并不存在的记录叫做“间隙GAP”
InnoDB 也会对这个“间隙”加锁这种锁机制就是所谓的间隙锁next-key锁、【危害】
因为Query执行过程中通过范围查找的话他会锁定整个范围内所有的索引键值即使这个键值不存在。
间隙锁有同一个比较致命的弱点就是当锁定一个范围键值之后即使某些不存在的键值也会被无辜的锁定而造成在锁定的时候
无法插入锁定键值范围内的任何数据。在某些场景下这可能会对性能造成很大的损失。
######################面试题常考如何锁定一行##################面试题如何锁定一行
1.session1 - begin; select * from test_innodb_lock where a8 for update;session2 - update test_innodb_lock set b8001 where a8;session1 - commit;解释select xxx... from XX... for update;锁定某一行后其他的操作会被阻塞直到锁定行的会话提交commit;######################案例结论##################
案例总结innodb存储引擎由于实现了行级锁定虽然在锁定机制的实现方面所带来的性能损耗可能比表级锁定会更好一些但是在整体并发处理能力方面要远远优于myISAM的表级锁定。
当系统并发量较高的时候innodb的整体性能和myISAM相比就会有比较显著的优势了。但是innodb的行级锁定同样也有其脆弱的一面(行锁变表锁)当我们使用不当的时候可能会让innodb的整体性能表现不仅不能比myISAM高甚至会更差
#######################行锁分析######################
行锁分析
【如何分析行锁定】
通过InnoDB_row_lock状态变量来分析系统上的行锁的争夺情况
mysql show status like innodb_row_lock%;
--------------------------------------
| Variable_name | Value |
--------------------------------------
| Innodb_row_lock_current_waits | 0 |
| Innodb_row_lock_time | 20428 |
| Innodb_row_lock_time_avg | 4085 |
| Innodb_row_lock_time_max | 5453 |
| Innodb_row_lock_waits | 5 |
--------------------------------------对各个状态量的说明
Innodb_row_lock_current_waits当前正在等待锁定的数量
Innodb_row_lock_time从系统启动到现在锁定的总时间长度
Innodb_row_lock_time_avg每次等待所花费的平均时间
Innodb_row_lock_time_max从系统启动到现在等待最长的一次所花的时间
Innodb_row_lock_waits系统启动后到现在总共等待的此时对于这五个状态变量比较重要的是以下三项
Innodb_row_lock_time_avg等待平均时长
Innodb_row_lock_waits等待总次数
Innodb_row_lock_time等待总时长尤其是当等待次数很高而且每次等待时长也不小的时候我们就需要分析系统中为什么会有如此多的等待
然后根据分析结果着手制定优化计划。 优化建议 尽可能让所有数据检索都通过索引来完成避免无索引行锁升级为表锁 合理设计索引尽量缩小锁的范围 尽可能较少检索条件避免间隙锁 尽量控制事务大小减少锁定资源量和时间长度 尽可能低级别事务隔离 页锁 开销和加锁时间界于表锁和行锁之间会出现死锁锁定粒度界于表锁和行锁之间并发度一般。 了解一下即可 转载于:https://www.cnblogs.com/weixiaotao/p/10741500.html