本文介绍事务特性,结合MySQL的经验讲解。MySQL使用InnoDB引擎。
事务(Transaction)是由一系列对系统中的数据进行访问与更新的操作所组成的一个程序执行逻辑单元(Unit),狭义上指数据库事务。
1. 事务4大特性
1.1 原子性(Atomicity)
事务一个原子操作单元。要么成功,要么失败。
1.2 一致性(Conisitency)
事务的执行使数据库从一种状态到另一种状态,不存在中间状态。不存在部分数据写入数据库的现象。
1.3隔离性(Isolation)
事务与事务操作独立,不会相互影响,SQL规范定义了4个事务隔离级别
1.3.1 未授权读取
读未提交(Read Uncommitted),允许脏读,读取其他事务未提交的数据
1.3.2 授权读取
读已提交(Read Committed),只允许读取其他事务已提交的数据。不会出现脏读。可能会出现不可重复读与幻读。
1.3.3 可重复读取,MySQL默认隔离级别。
可重复读取(Repeatable read),事务处理过程中,多次读取同一数据,值与事务开始时刻一致。可能会出现幻读。
MySQL提供next-key防止幻读。
MySQL 如果检索条件有索引(含主键索引),默认加锁方式是next-key 锁;如果检索条件没有索引,更新数据时会锁住整张表。一个间隙(GAP)被事务加了锁,其他事务是不能在这个间隙写入数据,防止幻读
1.3.4 串行化
串行化(Serializable),顺序执行,不存在一致性问题。
- 脏读:表示一个事务能够读取另一个事务中还未提交的数据。如:事务A尝试插入记录1,该事务还未提交,事务B尝试读取记录1,成功读取到记录1的记录;
- 不可重复读:表示当前事务对同一记录的两次重复读取结果不一致。如:事务A首先读取记录1,之后事务B修改提交记录1,然后事务A再次读取记录1,事务A发现两次读取的结果不一致;
- 幻读:表示当前事务修改时,其他事务做了新增或删除操作,导致部分数据未修改成功。如:事务A在更新几条记录的某些值时,由于事务B新增了记录1,或删除了记录1,事务A提交后发现有记录1未修改,或记录1已删除。
不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行(行锁),解决幻读需要锁表(表锁)
设置和查询MySQL隔离级别
-- 设置事务隔离级别,四种隔离级别:Read uncommitted,Read committed,Repeatable read,Serializable
SET session TRANSACTION ISOLATION LEVEL Read uncommitted;
-- 查看当前会话的事务隔离级别
select @@tx_isolation;
1.4 持久性(Durability)
事务一旦提交,永久保存在数据库里,持久化到磁盘等存储介质。
2. MySQL锁机制
MySQL数据库实现的锁都是悲观锁
共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE
排他锁(X):SELECT * FROM table_name WHERE ... FOR UPDATE
2.1 表锁
未命中索引
2.2 行锁
InnoDB行锁是通过给索引上的索引项加锁来实现的,只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁
2.3 间隙锁(next-key),可防止幻读。
当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁
比如:
select * from table_name where id < 100 for update;
3 乐观锁
所谓乐观锁就是约定,不加锁,比如库存>0,版本号等
3.1 CAS,典型的乐观锁
比如:update xxx set a=1 where id = xxx and a=2
比对a是不是2;是2,set a=1
这就会出问题,ABA问题,其他事务将a改为n,然后再改为2,此时需要版本号控制
update xxx set a=1 where id = xxx and a=2 and version < 10001 (版本号大才update,svn控制原理)
精简一下,使用库存控制
update xxx set num = num-1 where num-1 >= 0;
4. MySQL MyISAM存储引擎
锁机制由MySQL提供的表级锁定实现
表共享读锁(Table Read Lock)和表独占写锁(Table Write Lock)。
对MyISAM表的读操作,可以同时读取表,但不能写入表;
对MyISAM表的写操作,阻塞未持有锁的线程对表的读和写操作;
MyISAM表的读操作与写操作之间,以及写操作之间是串行的。
总结
以上是书本知识 的总结,与笔者部分实践的总结,有不对的地方请指出
来源
《MySQL性能优化与架构设计》
《深入浅出MySQL》