日记 - Mysql数据库的基础知识二

事务

    事务就是一组SQL查询,作为一个独立的工作单元。应用时,数据库执行该组查询,如果任何一条语句失败或者无法执行,那么所有的语句都不会执行。也就是说,事务内的语句,要么全部执行成功,要么全部执行失败。

    以银行的转账应用来举例:

1,检查余额是否能满足转账金额。

2,从余额中扣除转账金额。

3,给目标帐号余额增加转账金额

    上面三个步骤必须在一个事务中,任何一个步骤失败,就必须回滚所有的步骤,不然...就可以刷钱了。这里就不举例事务的语句了,也不描述上述步骤的必要性,请自行逻辑脑补。

    一个运行良好的事务处理系统,必须具备以下四个标准特征(ACID特性)。

原子性:一个事务必须被视为一个不可分割的最小的工作单元。

一致性:数据库总是从一个一致性的状态转换到另外一个一致性的状态。

隔离性:通常来说,一个事务所做的修改在最终提交以前,对其他事务是不可见的。

持久性:一旦事务提交,则其所做的修改就会永久保存到数据库中。

    就像锁粒度的升级会增加系统开销一样,这种事务处理过程中的额外的安全性,也会需要数据库系统做更多的额外工作。MySQL的存储引擎架构可以根据业务需要来选择存储引擎,一个非事务型的存储引擎,可以提供更高的性能,这都是可以自主选择的,是其优势。

隔离级别

隔离比较复杂。在SQL标准中定义了四种隔离级别,每一种级别都规定了一个事物中所做的修改,哪些在事务内和事务间是可见的,哪些是不可见的。较低级别的隔离通常可以执行更高的并发,系统的开销也更低。(每种存储引擎实现的隔离级别不尽相同,请根据自己的存储引擎查阅相关手册)

    以下简单介绍一下四种隔离级别:

READ UNCOMMITTED (未提交读)

    在READ UNCOMMITTED 级别,事务中的修改,即使没有提交,对其他事务也都是可见的。事务可以读取未提交的数据,被称为脏读(Dirty Read)。这个级别会导致很多问题,性能上虽然优势却也不太多,但却缺乏其他级别的很多好处,除非真的非常必要,在实际应用中一般很少使用。

READ COMMITTED (提交读)

    大多数数据库系统的默认隔离级别都是READ COMMITTED (但MySQL不是)。它满足隔离性里的一个简单定义:一个事务从开始直到提交之前,所作的任何修改对其他事务都是不可见的。这个级别有时候也叫做不可重复读,因为两次执行同样的查询,可能会得到不一样的结果。

REPEATABLE READ (可重复读)

    它解决了脏读的问题,该级别保证了在同一个事务中多次读取同样记录的结果是一致的。但是理论上,可重复读隔离级别还是无法解决另外一个幻读(Phantom Read)问题。幻读指的是,当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行(Phantom Row)。InnoDB和XtraDB存储引擎通过多版本并发控制(MVCC, Multiversion Concurrency Control)解决了幻读问题。

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

SERIALIZABLE (可串行化)

    这是最高隔离级别。它通过强制事务串行执行,避免了前面说的幻读的问题。简单来说,它会在读取的每一行数据上都加锁,所以可能导致大量的超时和锁争用的问题。很少用到该隔离,只有在非常需要确保数据的一致性而且可以接受没有并发的情况下,才考虑采用该级别。

 

(我额外加了点内容上去)

死锁

死锁是指多个事务在同一资源上互相占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。当多个事务试图以不同的顺序来锁定资源时,就可能会产生死锁。多个事务同时锁定同一个资源时,也会产生死锁。

    数据库系统实现了各种死锁检测和死锁超时机制。越复杂的系统,比如InnoDB存储引擎,越能检测到死锁的循环依赖,并立即返回一个错误。InnoDB目前处理死锁的方法是,将持有最少行级排他锁的事务进行回滚。

    死锁的产生有双重原因:有些是因为真正的数据冲突,这很难避免,但有些则完全是由于存储引擎的实现方式导致的。

 MySQL中的事务

mysql提供了两种事务型的存储引擎:InnoDB和NDB Cluster。

    首先mysql默认采用自动提交:如果不是显式的开始一个事务,则每个查询都被默认当作一个事务执行提交操作。

    在当前连接中,可以通过设置AUTOCOMMIT 变量来启用或者禁用自动提交模式,1或者ON 表示启用,0或者OFF 表示禁用。例如:

mysql> SHOW VARIABLES LIKE 'AUTOCOMMIT';

mysql> SET AUTOCOMMIT = 1;

    当AUTOCOMMIT=0 时,也就是自动提交关闭时,所有的查询都是在一个事务中,直到显式地执行COMMIT 提交或者ROLLBACK 回滚,该事务结束,同时又开始了另一个新事务。

    修改AUTOCOMMIT 对非事务型的表,比如MyISAM 或者内存表,不会有任何影响。对于这样的表来说,没有COMMIT 或者ROLLBACK 的概念,也可以说是一直处于AUTOCOMMIT 启用的模式。

    另外还有一些命令,在执行之前会强制执行COMMIT 提交当前的活动事务。典型的例子,在数据定义语言(DDL)中,如果是会导致大量数据改变的操作,比如ALTER  TABLE,就是如此。当然除此之外还有其他类似LOCK   TABLES 语句也会导致同样结果。

    MySQL可以通过执行以下命令来设置隔离级别:

mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

    新的隔离级别辉仔下一个事务开始的时候生效。可以在配置文件中设置整个数据库的隔离级别,也可以只改变当前会话的隔离级别。

    MySQL能够识别所有的4个ANSI隔离级别,InnoDB引擎也支持所有的隔离级别。

不要再事务中混合使用存储引擎

    如果事务需要回滚,非事务型的表上的变更无法撤销,这种情况很难修复,这种时候数据库甚至不会报错和提醒。

隐式和显式锁定

    InnoDB采用的是两阶段锁定协议。在事务执行过程中,随时都可以执行锁定,锁只有在执行COMMIT 或者ROLLBACK 的时候才会释放。前面描述的都是隐式锁,InnoDB会根据隔离级别在需要的时候自动加锁。

猜你喜欢

转载自lcl088005.iteye.com/blog/2272266