mysql系列之事务和锁

    2015年10月29日 doc mysql 字数:1934

innodb引擎支持事务,事务主要概念、使用、锁这三点。

概念

是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成

事务的ACID特性

1、A (Atomicity) 原子性

事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。

2、C (Consistency)一致性

事务在完成时,必须使所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。事务结束时,所有的内部数据结构(如 B树索引或双向链表)都必须是正确的。

3、I (Isolation) 隔离性

并发事务所做的修改必须与任何其他并发事务所做的修改隔离。事务识别数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是第二个事务修改它之后的状态,事务不会识别中间状态的数据。

4、D (Durability) 持久性

事务完成之后,它对于系统的影响是永久性的。该修改即使出现系统故障也将一直保持。

场景

BEGIN a transaction: 设置事务的起始点

COMMIT a transaction: 提交事务,使事务提交的数据成为持久,不可更改的部分.

ROLLBACK a transaction:撤消一个事务,使之成为事务开始前的状态.

SAVE a transaction:建立一个标签,做为部分回滚时使用,使之恢复到标签初的状态.

事务冲突场景

锁是数据库引擎用来同步多个用户同时对同一个数据块的访问的一种机制。尤其适用于事务使用中,多个事务共同操作一份数据,这样的条件可以衍生出很多的情景如下

1、脏读

某个事务读取的数据是另一个事务正在处理的数据。而另一个事务可能会回滚,造成第一个事务读取的数据是错误的。

2、不可重复读

在一个事务里两次读入数据,但另一个事务已经更改了第一个事务涉及到的数据,造成第一个事务读入旧数据。

3、幻读

幻读是指当事务不是独立执行时发生的一种现象。例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。

4、更新丢失

多个事务同时读取某一数据,一个事务成功处理好了数据,被另一个事务写回原值,造成第一个事务更新丢失。

锁模式

1、共享锁

共享锁(S 锁)允许并发事务在封闭式并发控制下读取 (SELECT)资源。 资源上存在共享锁(S锁)时,任何其他事务都不能修改数据。读取操作一完成,就立即释放资源上的共享锁(S锁),除非将事务隔离级别设置为可重复读或更高级别,或者在事务持续时间内用锁定提示保留共享锁(S锁)。

2、排它锁

排他锁(X 锁)可以防止并发事务对资源进行访问。排他锁不与其他任何锁兼容。使用排他锁(X锁)时,任何其他事务都无法修改数据;仅在使用 NOLOCK提示或未提交读隔离级别时才会进行读取操作。

3、更新锁

更新锁在共享锁和排他锁的杂交。更新锁意味着在做一个更新时,一个共享锁在扫描完成符合条件的数据后可能会转化成排他锁。 这里面有两个步骤:

  1. 扫描获取Where条件时。这部分是一个更新查询,此时是一个更新锁。
  2. 如果将执行写入更新。此时该锁升级到排他锁。否则,该锁转变成共享锁。

更新锁可以防止常见的死锁。

锁的超时等待

SET LOCK_TIMEOUT 4000 用来设置锁等待时间,单位是毫秒,4000意味着等待 4秒。

可以用select @@LOCK_TIMEOUT查看当前session的锁超时设置。-1 意味着 永远等待。

T1: begin tran

udpate table set column1='hello' where id = 10

T2: set lock_timeout 4000

select * from table wehre id = 10

T2执行时,会等待T1释放排他锁,等了4秒钟,如果T1还没有释放排他锁,T2就会抛出异常: Lock request time out period exceeded.

如何避免死锁

  • 使用事务时,尽量缩短事务的逻辑处理过程,及早提交或回滚事务;
  • 设置死锁超时参数为合理范围,如:3分钟-10分种;超过时间,自动放弃本次操作,避免进程悬挂
  • 一般不要修改SQL SERVER事务的默认级别。不推荐强行加锁
  • 优化程序,检查并避免死锁现象出现;
    • 合理安排表访问顺序
    • 在事务中尽量避免用户干预,尽量使一个事务处理的任务少些。
    • 采用脏读技术。脏读由于不对被访问的表加锁,而避免了锁冲突。在客户机/服务器应用环境中,有些事务往往不允许读脏数据,但在特定的条件下,我们可以用脏读。
    • 数据访问时域离散法。数据访问时域离散法是指在客户机/服务器结构中,采取各种控制手段控制对数据库或数据库中的对象访问时间段。主要通过以下方式实现: 合理安排后台事务的执行时间,采用工作流对后台事务进行统一管理。工作流在管理任务时,一方面限制同一类任务的线程数(往往限制为1个),防止资源过多占用; 另一方面合理安排不同任务执行时序、时间,尽量避免多个后台任务同时执行,另外,避免在前台交易高峰时间运行后台任务
    • 数据存储空间离散法。数据存储空间离散法是指采取各种手段,将逻辑上在一个表中的数据分散到若干离散的空间上去,以便改善对表的访问性能。主要通过以下方法实现: 第一,将大表按行或列分解为若干小表; 第二,按不同的用户群分解。
    • 使用尽可能低的隔离性级别。隔离性级别是指为保证数据库数据的完整性和一致性而使多用户事务隔离的程度,SQL92定义了4种隔离性级别:未提交读、提交读、可重复读和可串行。如果选择过高的隔离性级别,如可串行,虽然系统可以因实现更好隔离性而更大程度上保证数据的完整性和一致性,但各事务间冲突而死锁的机会大大增加,大大影响了系统性能。
    • 使用Bound Connections。Bound connections 允许两个或多个事务连接共享事务和锁,而且任何一个事务连接要申请锁如同另外一个事务要申请锁一样,因此可以允许这些事务共享数据而不会有加锁的冲突。
    • 考虑使用乐观锁定或使事务首先获得一个独占锁定。

参考文档

http://www.ccidnet.com/product/techzt/sisuo/ http://www.cnblogs.com/zhouqianhua/archive/2011/04/15/2017049.html http://blog.csdn.net/zztfj/article/details/7879613 http://tech.meituan.com/innodb-lock.html