事务
InnoDB支持事务也就是ACID原子性,一致性,隔离性,持久性。
并发事务
优势:
并发事务能大大增加数据库资源的利用率,提高数据库系统的事务吞吐量,从而可以支持更多的用户。
问题:
更新丢失:当多个事务选择同一行,然后基于最初选定的值更新,后续事务会覆盖前面的更新。
脏读:一个事务正在更改一条记录,在事务提交前,另一个事务读取了这个事务未提交的数据,并依赖这个数据做进一步和粗粒,就会产生未提交的数据依赖关系。
不可重复读:一个事务在读取某些数据后一段时间再次读取,发现数据已经改变或者删除。
幻读:一个事务按相同的查询条件重新读取以前检索过的数据,其他事务这时插入了满足查询条件的新数据,导致读取的数据不准确。(未提交的事务数据是不能产生依赖关系的,是脏数据。
解决方案:读取数据前,对其加锁,防止其他事务对数据进行修改。
事务隔离级别
MVCC,通过一定机制生成一个数据请求时间点的一致性数据快照,并用这个快照来提供一定级别的一致性读取。关于MVCC的介绍详见:https://blog.dugwang.com/?p=373
四种隔离级别:未提交读,已提交读,可重复读,可序列化。
InnoDB的锁
InnoDB的行锁模式
共享锁:允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁(其他事务获得排它锁,意味着这个共享锁将失效)
排它锁:允许获得排他锁的事务更新数据,,阻止其他事务取得相同数据集的共享锁和排他写锁。
小结:共享锁的期间,其他事务也可以获取共享锁。排他锁期间,其他事务不能获取共享锁和排他锁,只可以做简单的查询。
InnoDB的加锁方法
1、对于增删改操作,InnoDB会自动给涉及数据集加排他锁;对于普通SELECT语句,不会加锁。
2、可以通过以下语句给记录集加共享锁和排他锁
2.1、共享锁:select * from table_name where ... LOCK IN SHARE MODE.
2.2、排他锁:select * from table_name where ...FOR UPDATE.
2.3、共享锁的问题?用LOCK IN SHARE MODE加锁,主要是用来确认数据是否存在,并确保没人对这个数据进行其他操作。但是如果当前事务也需要对该记录进行更新操作,则很可能造成死锁(其他事务此时也给该记录加了个共享锁,并且对该行进行更新,就会造成同时2个循环等待的锁,死锁退出)。
2.4、如何处理?对于锁定行记录后需要进行更新操作的应用,应该使用select ... for update方式获得排他锁。
InnoDB行锁的实现方式
1、InnoDB行锁是通过给索引上的索引项加锁来实现的,所以只有通过索引条件检索数据,才使用行级锁,否则会用表锁。
2、因为是使用索引加锁,所以虽然不是同一行记录,如果使用同一个索引键,还是会阻塞。
3、可能造成全表扫描的问题?a表的name字段有索引,但是name是varchar类型的,如果where条件后不跟引号,会造成强制类型转换,执行全表扫描。
间隙锁
用范围查询或者查询一个不存在的数据并加锁时,InnoDB不仅会对已存在的数据加锁,也会对范围内的不存在的数据加间隙锁,这是为了避免幻读。所以,应尽量避免给范围查询加锁。
恢复和复制对InnoDB锁机制的影响
1、MySQL通过binlog记录执行的sql语句,一般的恢复是SQL语句级别的,就是重新执行binlog中的sql语句。
2、MySQL的binlog是按照事务提交的先后顺序记录的,恢复也是按照这个顺序执行。
3、所以,MySQL的恢复要求事务在提交前不允许其他事务插入新数据,因为会影响到恢复是时数据的正确性。
InnoDB
什么情况下使用表锁
1、事务需要更新大部分或者全部数据,表又比较大。
2、事务涉及多个表,比较复杂,可能引起死锁。
如何尽量避免死锁
1、尽量使用较低的隔离级别
2、精心设计索引,使用索引访问数据
3、选择合理的事务大小
4、给记录集显式加锁时,最好一次申请足够级别的锁
5、不同程序访问同一组表,尽量约定相同的顺序。
6、尽量使用相等条件
7、除非必须,查询时不要显式加锁
8、特殊事务,用你表锁来提高处理速度和减少死锁的可能。
网友评论