什么是事务
事务是一组DML(数据管理语言),这些语言在逻辑上存在相关性,事务的一组DML,要么全部成功,要么全部失败。
事务需要满足以下四个属性。
1).原子性:一个事务的所有DML语言,要么全部成功,要么全部失败,如果错误,则回滚到最开始,重新执行。
2).一致性:多个事务并形时,事务必须按照顺序串行执行,并且多个事务不能相互干扰。
3).隔离性:事务并行执行时,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致,这是由隔离级别决定的。
隔离级别有以下四个级别。
1).读未提交:read uncommitted。
2).读提交:read committed。
3).可重复读: repeatable read。
4).串行化:Serializable。
隔离级别从上到下,隔离级别主键增加。
4).持久性:事务提交后,对数据库的改变就是永久的,及被刷到磁盘,即使此时数据库故障,也不会导致事务丢失。
某些数据库引擎不支持事务。
show engines\G,查看每个引擎是否支持事务。
事务的提交方式
在mysql中,即使是一个sql语句,也是一个事务,事务默认自动提交,可以使用以下sql语句查看事务是否自动提交,autocommit是mysql中的一个全局变量。
show variables like ‘autocommit’
可以使用以下sql语句设置事务是否可以自动提交。
set autocommit=0/1
0代表off,1代表on。
将事务设置为自动提交,则用户输入的每个sql语句都会被持久化,同时满足原子性,大部分数据库都是开启自动提交。
如果将autocommit设置为off,则代表每个sql语句只要未被提交,就不会被持久化,可以随时设置断点rollback,回滚到之前。
在事务中设置断点,savepoint p_name。
可以使用rollback [p_name]回滚到某个断点处,或者直接回滚到事务开始。
事务的启动和提交
事务也可以手动开启和提交。
begin / start transaction 启动一个事务。
commit 提交一个事务。
事务隔离级别详解
隔离级别有以下四个。
1).读未提交:read uncommitted。
2).读提交:read committed。
3).可重复读: repeatable read。
4).串行化:Serializable。
1).读未提交:read uncommitted。
该隔离状态是最第的隔离状态,在多事务并发时,当一个事务进行了表的修改操作,则另一个事务也可以查看到修改的结果。
当一个事务进行了表的修改操作,则另一个事务也可以查看到修改的结果,这种情况叫做脏读,是不合理的,同时,无法屏蔽插入操作的数据,这种现象叫做幻读。
2).读提交:read committed。
该隔离状态下,多事务并发时,只有一个事务递交了,其他事务才能看到表的修改结果。
这种情况下可能导致查询结果不准确。
3).可重复读: repeatable read。
该隔离状态下,多事务并发时,某个事物进行了一次快照读后,每次读到的结果都是第一次快照读读到的结果。
4).串行化:Serializable。
该隔离级别下,多事物是串行执行的,一个客户端来到执行指令时,会获得一把锁,直到得到锁的客户端提交,释放这吧锁,其他客户端才能进行操作。
这样的隔离状态下,会导致运行效率低下。
查看隔离级别
我们也可以通过sql语句查看隔离级别,存在两种隔离级别。
1).全局隔离级别。
select @@global.tx_isolation 查看全局隔离级别。
每个mysql的会话都会以全局隔离级别为模板。
2).会话隔离级别。
select @@session.tx_isolation 查看会话隔离级别。
会话隔离级别是当前会话使用的隔离级别。
可以通过指令设置当前会话和全局会话。
set global/session transaction isolation level…
MVCC详解
MVCC(多版本并发控制)是数据库管理系统用于处理并发的先进技术,其维护了数据的多个版本,使得不同事物在读取数据时能够看到与自己事物开始时间相一致的数据快照。
表中存在三个隐藏字段。
1).DB_TRX_ID:最近修改的事物ID。
2).DB_ROLL_PTR:回滚指针,指向上一个版本。
3).DB_ROW_ID:如果未有主键,则该字段就是表的自增主键,表会以该主键生成一个聚簇索引。
在mysql的缓冲区中,存在一块空间,记录版本信息,叫做undo log,从而形成一个版本链,所谓的回滚,就是让过去的内容覆盖现在的内容。
我们会将update或delete的数据记录到版本链中,所谓的delete并不是直接删除某一行,而是设置某个标记位,而insert操作不会被记录到版本链中。
我们需要了解两种不同的读。
1).当前读
及读取当前的表中的数据,比如RU隔离级别。
2).快照读
及读取过去版本的内容,比如RR和RC隔离级别。
当前事务能够快照读到的内容取决于一个结构体(read view)读视图结构体。
该结构体内存在一些字段,与当前时间能够读到的事务有关的结构体。
1.m_low_limit_id:大于等于这个事务的id的事务无法被读到,因为这些事务在当前事务运行时还未开始。
2.m_up_limit_id:小于这个事务的id的事务是历史提交过的,应该看到。
3.m_create_trx_id:代表当前事务的id。
4.m_ids:创建该视图时,活跃的事务id。
事务id是递增的m_low_limit_id是当前时刻尚未分配的事务id。
m_up_limit_id是当前运行事务的id最小值。
只有在两者之间的事务是快照的内容。
举个例子。
上述例子中,快照读的范围是小于up_limit_id的事务,以及在快照读时开始运行的事务中以及提交的事务,所以上述例子中,事务4可以被读到。
RR和RC的区别
RR 可重复读在第一次快照读时,生成快照,并且RR隔离级别下,只能有一个读视图。
1).提交后在select,另一个事务的update读到了。
2).没提交并且select,另一个事务的update没读到。
RC 读提交情况下,每次快照读都会生成一个读视图。