事务
RDMS一般都遵循ACID原则,即:
- atomicity(原子性):要么都执行,要么都不执行
- consistency(一致性):
- isolation(隔离性):
- durability(持久性):一旦一个事务完成,就是持久的
数据一致性是最终目标,RDMS追求强一致性。
在 MySQL 命令行的默认设置下,事务都是自动提交的,即执行完 SQL 语句后紧接着就会执行 COMMIT
操作。要显式地开启一个事务务须使用命令 BEGIN 或 START TRANSACTION
,或者执行命令 SET AUTOCOMMIT=0
,用来禁止使用当前会话的自动提交。
并非所有的存储引擎都支持事务,实际应用中要根据业务是否需要事务处理来选择合适的存储引擎,对于不需要事务的查询类应用,选择一个非事务型的存储引擎,如MyISAM,可以获得更高的性能。
隔离级别
问题 | 描述 |
---|---|
脏读 (dirty read) | A、B事务交叉时,A事务读取到了B事务未提交的更改 (读取到未提交的dirty数据) |
不可重复读 (unrepeatable read) | A、B事务交叉,A事务尚未提交时,A事务读取到了B事务提交的更改数据 (两次执行同样的查询会得到不同的结果) |
幻象读 (phantom read) | A、B事务交叉,A事务读取到了B事务新增的数据 (A两次查询结果不同,第二次查询到了B新插入的“幻行”phantom row) |
第一类丢失 | |
第二类丢失 |
注意区分幻象读和不可重复读,前者是读到其他事务提交的新增数据,后者是读到了已提交事务的更改数据。为了避免这两种问题,所采取的策略也有所不同:防止读取更改数据只需对操作数据加行级锁;而防止读到新增数据需要添加表级锁。
隔离级别是数据库为用户提供的自动锁机制,用户指定会话的隔离级别,数据库就会分析事务中的SQL语句,自动为事务操作添加合适的锁。
不同的隔离级别可以解决不同层次的问题,越高的隔离级别可以避免更多的并发问题,但代价是并发性能和吞吐量的降低,到了Serializable级别会强制事务串行执行,如果一个事务不commit,另一个事务是无法更改数据的。
ANSI SQL隔离级别由低到高依次为:
READ-UNCOMMITTED
(读取未提交的内容):READ-COMMITTED
(读取提交内容):REPEATABLE-READ
(可重复读):MySQL默认隔离级别;
这里要理清概念,MySQL服务器和存储引擎不是一个层面的东西,MySQL默认的引擎是InnoDB,而InnoDB实现了ANSI标准的四个隔离级别,默认是repeatable read,所以才可以说MySQL默认隔离级别是repeatable read;SERIALIZABLE
(可串行化):
由上可知MySQL默认隔离级别没有解决幻象读的问题,在InnoDB引擎中通过MVVC(多版本并发控制)来解决:
不同隔离级别存在的问题
隔离级别设置命令:
set tx_isolation='READ-UNCOMMITTED'; #设置隔离级别
set session transaction isolation repeatable read; #设置隔离级别,功能同上
select @@tx_isolation; #查询隔离级别
start transaction; #开始事务
rollback; #回滚事务
commit; #提交事务