mysql事务与锁

事务控制

start transaction|begin [work]
commit [work] [and [no] chain] [[no] release]
rollback [work] [and [no] chain] [[no] release]
set autocommit={0|1}

分布式事务只支持InnoDB存储引擎。

两阶段

事务ACID

  • 原子性(Atomicity):要么全执行,要么全不执行
  • 一致性(Consistent):事务开始和完成时,数据必须保持一致状态
  • 隔离性(Isolation):不受外部并发操作影响
  • 持久性(Durable):数据修改时永久性的

术语

  • 更新丢失:后面的更新覆盖了前面的更新
  • 脏读:修改未提交之前,另一个事务去读了
  • 不可重复读:一个事务内,两个时间点读的数据不一致
  • 幻读:一个事务按照相同的查询条件读取以前检索过的数据,却发现其他事务插入了满足其查询条件的数据

事务的隔离级别

级别 脏读 不可重复读 幻读
可读取未确认Read uncommitted 可能 可能 可能
可读取确认Read committed 不可能 可能 可能
可重复读 不可能 不可能 可能
可串行化(序列化)Serializable 不可能 不可能 不可能

MySQL的默认隔离级别是可重复读

mysql锁

各存储引擎的锁

  • MyISAM和MEMORY存储引擎采用的是表级锁
  • BDB存储引擎采用的是页面锁,但也支持表级锁
  • InnoDB存储引擎支持行级锁,也支持表级锁
特性
表级锁 开销小,加锁快;不会出现死锁;锁定粒度大,发生冲突的概率最高,并发度最低。
行级锁 开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高
页面锁 开销和加锁时间介于表锁和行锁之间;会出现死锁;锁定粒度介于表锁和行锁之间,并发度一般

MyISAM的表锁

查询表级锁争用情况

show status like 'table%';

如果Table_locks_waited的值比较高,则说明存在着较严重的表级锁争用情况。

表级锁的锁模式

  • 表共享读锁
  • 表独占写锁

MyISAM总是一次获得sql语句所需要的全部锁,这是MyISAM表不会出现死锁的原因。

并发插入

MyISAM存储引擎有一个系统变量concurrent_insert

concurrent_insert值 说明
0 不允许并发插入
1 如果表中没有空洞,MyISAM允许在一个进程读表的同时,另一个进程从表尾插入记录
2 无论MyISAM表中有没有空洞,都允许在表尾并发插入记录

锁调度

  • 通过设置启动参数low-priority-updates使MyISAM引擎默认给予读请求以优先的权利
  • 通过执行命令set low-priority-updates=1,使得该连接发出的更新请求优先级降低
  • 通过指定insert,update,delete语句的low_priority属性,降低该语句的优先级

查询优先可以解决查询相对重要的应用(用户登录)中读锁等待严重的问题。读写冲突,可以给系统参数max_write_lock_count设置一个合适的值,当一个表的读锁达到这个值后,mysql就暂时将写请求的优先级降低,给读进程一定获得锁的机会。一些需要长时间运行的查询操作,也会使写进程”饿死”,尽量避免出现长时间运行的查询操作,对于复杂的查询,不要一个sql写完,否则执行时间可能较长。在可能的情况下,尽量用中间表等措施对sql语句做一定的分解,使每一步查询时间都比较短,从而减少锁冲突。统计类的sql,可以安排在夜间空闲时刻执行。

InnoDB锁问题
InnoDB与MyISAM的最大不同有两点

  • 支持事务
  • 采用行级锁

获取InnoDB行锁争用情况

show status like 'innodb_row_lock%'

如果InnoDB_row_lock_waits和InnoDB_row_lock_time_avg的值比较高,则锁争用比较严重。

查看锁等待情况

select * from innodb_locks \G;

设置InnoDB Monitors观察锁冲突情况

create table innodb_monitor(a int) engine=innodb;

show engine innodb status\G;

drop table innodb_monitor;

InnoDB的行锁

  • 共享锁(S):类似读锁
  • 排他锁(X):类似写锁

表锁,意向锁

  • 意向共享锁(IS)
  • 意向排他锁(IX)
当前模式\是否兼容\请求锁模式 X IX S IS
X 冲突 冲突 冲突 冲突
IX 冲突 兼容 冲突 兼容
S 冲突 冲突 兼容 兼容
IS 冲突 兼容 兼容 兼容

InnoDB行锁实现方式

InnoDB行锁是通过给索引上的索引项加锁来实现的,如果没有索引,InnoDB将通过隐藏的聚簇索引来对记录加锁,InnoDB行锁分为3中情形。

  • Record lock:对索引项加锁
  • Gap lock:对索引项之间的”间隙”、第一条记录前的”间隙”或最后一条记录后的”间隙”加锁。
  • Next-key lock:前两种的组合,对记录及前面的间隙加锁。

InnoDB这种行锁实现特点意味着,如果不通过索引条件检索数据,那么InnoDB将对表中的所有记录加锁,实际效果跟表锁一样。

next-key锁

范围条件检索数据,符合条件的数据行会加锁,条件范围内的间隙也会加锁,比如:select * from emp where empid>100 for update;其中,empid的值分别是1,2,…,100,101,InnoDB不仅会对符合条件的101记录加锁,也会对empid大于101(这些记录不存在)的间隙(GAP)加锁。一方面为了防止幻读,另一方面,为了满足其恢复和复制的需要。注意:范围更新,无论出于那个隔离级别都使用next-key锁。

你可能感兴趣的:(mysql)