mysql事务
可以说无论去哪里面试mysql的事务和锁一定会被问到的,要回答并答的优雅
事务
事务的概念:易主原子性的sql查询,或者说一个独立的工作单元。如果数据引擎能成功的对数据库应用该组查询的全部语句,那么就执行改组查询,如果其中一条语句因为其他原因无法执行,那么所有的语句都不会执行。事务内的语句要不全部执行,要么全部执行失败。(原子性我理解就是保证一系列操作像最基本的原子一样不能被拆分不能分开成功)
必须注意的是:事务是在一系列能力和基础功能下实现的,如果系统没有经过ACID的严格测试,空谈事务是没有意义的。
原子性(atomicity)
一个事务必须呗是谓一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务,不可能只执行其中的一部分这就是事务的原子性。
还是上面加黑的那句话,事务的定义也是基于原子性的,没有实现原子性就不会达成事务的定义
一致性(consistency)
数据库总是从一个一致性的状态转换到另一个一致性状态,即使执行到一半一桶崩溃事务中的修改也不会保存到数据中。
隔离性(isolation)
正常来说一个事务所做的提交在最终提交以前,对其它的事务应该通常是不可见的数据库的事务隔离级别会影响可见性
持久性 (durability)
事务做了提交,所有修改就会永久的保存到数据库中。即使系统崩溃,锁保存的数据也不会丢失。持久性是个模糊的概念,因为实际上持久性有很多级别。有些持久性策略能够提供安全的保障,有些则不能。
例如:可以把系统提交数据倒数据库的数据想成存入到银行的钱,银行有很多安全措施,比放在家里安全,但是如果银行破产了或钱被抢劫啦怎么办。可能就要考虑做各种容灾,数据的冗余备份,没有百分之百的持久性我们只能应该用各种方法尽量保证数据的持久性和可恢复性。
事务小节
综上所述,数据库为了我们数据的安全做了这么多的努力和工作,一个实现了ACID的数据库,肯定需要更大的内存和磁盘空间,更强的cpu能力。
我们唯一要做好的就是根据自己的业务是否需要事务处理来选择合适的存储引擎,以获得更高的性能。及时引擎不支持事务也可以通过lock Tables 为应用提供一定程度的保护,如果这点程度都做不到,真的不好意思称自己为工程师。
事务的隔离级别
上面在说隔离性的时候提到了一个事务在提交之前,其它事务应该是通常不可见的,注意是通常不过sql标准为了应对我门的一些业务场景做了四种隔离界别
事务的隔离界别
隔离级别比想象跟复杂,SQL标准汇中定义了四种隔离级别,每一种级别都详细规定了一个事务中所做的修改在其它事务内和事务间是可见的,那些是不可兼得的,较低级别的隔离通常可以执行更高的并发,系统的开销也更低。
READ UNCOMMITED (未递交读)
未提交读中如果事务做了修改即使没有提交,其它事务也是可以看见的。事务读到未提交的数据被称为脏读。照成问题的同时并未提高性能,所以一般在应用中很少使用。
READ CIMMITED (提交读)
一个事务开始到未提交之前,可以看到其它事务在此期间做的修改。也可以称为不可重复读(因为在事务中,两次读取的数据可能被其它事务修改)
REPEATABLE READ(可重复度)
可重复读解决了脏读的问题,保证了在同一事务中多次读取同样的记录结果是一致的。但是还是会产生幻读
幻读,并不是说两次读取获取的结果集不同,幻读侧重的方面是某一次的 select 操作得到的结果所表征的数据状态无法支撑后续的业务操作。更为具体一些:select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读。
(InnoDbhe 和XtraDb)通过多版本并发控制(mvcc)解决了幻读问题。
SERIALIZABLE(可串行化)
SERIALIZABLE是最高的隔离界别,通过强制事务串行执行,避免了幻读,但是会照成大量的锁竞争,非常需要保证数据一致性切没有可以接受并发的情况下,考虑使用该级别。
死锁
死锁是指两个或者多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。当多个事务试图以不同的顺序锁定资源时候,就可能产生死锁。多个事务同时锁定同一个资源时,有也会产生死锁。
解决死锁问题,最简单的方法可能就是等到一个超时时间后放弃锁请求,显而易见这回影响性能,InnoDb可以检测到死锁依赖,并将持有最少行级排它锁的事务进行回滚。
锁的行为和顺序是会存储引擎相关的。以同样的顺序执行语句,有的引擎会死锁,有的不会。所以死锁产生有双重原因:有些是因为真正的数据冲突(很难避免),有些是完全由于存储引擎的实现方式导致的。
解除死锁只有部分或完全回滚一个事务才能打破死锁(有没有点珍珑棋局的感觉或者堵车必须有人倒车哈哈~)
事务日志
修改内存拷贝,再把修改行行为顺序记录到磁盘的事务日志中,而不是实时把数据写入磁盘,这样数据在后台可以慢慢刷回磁盘。
mysql中的事务
mysql支持了两总事务型存储引擎:InnoDb和NDB Cluster。还有一些第三方存储引擎支持事务,例如XtaDb和PBXT。
自动提交(AUTOCOMMIT)
自动提交打开如果不是显示的开始一个事务,则每个查询都被当作一个事务执行提交操作。同时也要也可以显示修改当前会话的隔离级别。
事务中混用存储引擎
不要在一个事务中混用存储引擎,否则不支持事务的引擎在事务回滚时候无法撤销,这时候数据很难恢复
隐式和显式锁定
InnoDb才用的是两阶段锁定协议,在事务的执行过程中,随时都可以锁定执行,锁只有在执行commit或roolback的时候才会释放,且同一个时刻释放,所有锁都是隐式锁定,InnoDb会根据隔离级别在需要的时候自动加锁。
对不支持事务的引擎可以显示的执行lock。但是建议有事务需求的使用innodb引擎,行级锁毕竟可以有更好的定恩那个。尽量不使用显示锁。
多版本并发控制
mvcc可以认为是行级锁的变种,它在很多情况下避免了加锁操作,所以开销更低。虽然实现机制不同,但大都实现了非阻塞的读操作,写操作也只锁定了必要的行。
mvcc 是通过保存数据在墨哥时间点的快照实现的,也就是不管需要执行多长时间,每个事物看到的数据都是一致的。根据事物开始的时间不同,每个事物对同一张表,同一时刻看到的数据可能是不一样的。
MVCC只在repeatedbale Read和read comitted 两个隔离级别下工作,其它的隔离级别都和mvcc不兼容。