什么是事务:
事务(Transaction)是并发控制的单位,是用户定义的一个操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单位。
通过事务,SQL Server能将逻辑相关的一组操作绑定在一起,以便服务器保持数据的完整性。
(当我们需要执行多个sql语句,我们需要用事务操作,保证sql要么全部成功,要么全部失败)
事务是怎么实现的?
https://blog.csdn.net/DuTianTian_csdn/article/details/82711094
借助::
undo log:(记录之前的值)
在操作任何数据之前,首先将数据备份到一个地方(这个存储数据备份的地方成为undo log)。
redo_log:(记录之后的值)
和undo log相反,redo log记录的是新数据的备份。在事务提交前,只要将redo log持久化即可,
不需要将数据持久化。当系统崩溃时,虽然数据没有持久化,但是redo log已经持久化。系统可以根据
redo log的内容,将所有数据恢复到最新的状态。
事务执行步骤:
事务通常是以BEGIN TRANSACTION开始,以COMMIT或ROLLBACK结束。
COMMIT表示提交,即提交事务的所有操作。具体地说就是将事务中所有对数据库的更新写回到磁盘上的物理数据库中去,事务正常结束。
ROLLBACK表示回滚,即在事务运行的过程中发生了某种故障,事务不能继续进行,系统将事务中对数据库的所有以完成的操作全部撤消,滚回到事务开始的状态。
数据库的四大属性
- 原性性(Actomicity):事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。
- 一致性(Consistent):在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以操持完整性;事务结束时,所有的内部数据结构(如B树索引或双向链表)也都必须是正确的。
- 隔离性(Isolation):数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。
- 持久性(Durable):事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。
事务并发调度的问题
- 脏读(dirty read):A事务读取B事务尚未提交的更改数据,并在这个数据基础上操作。如果B事务回滚,那么A事务读到的数据根本不是合法的,称为脏读。在oracle中,由于有version控制,不会出现脏读。
- 不可重复读(unrepeatable read):A事务读取了B事务已经提交的更改(或删除)数据。比如A事务第一次读取数据,然后B事务更改该数据并提交,A事务再次读取数据,两次读取的数据不一样。
- 幻读(phantom read):A事务读取了B事务已经提交的新增数据。注意和不可重复读的区别,这里是新增,不可重复读是更改(或删除)。这两种情况对策是不一样的,对于不可重复读,只需要采取行级锁防止该记录数据被更改或删除,然而对于幻读必须加表级锁,防止在这个表中新增一条数据。
- 第一类丢失更新:A事务撤销时,把已提交的B事务的数据覆盖掉。
- 第二类丢失更新:A事务提交时,把已提交的B事务的数据覆盖掉。
三级封锁协议
- 一级封锁协议:事务T中如果对数据R有写操作,必须在这个事务中对R的第一次读操作前对它加X锁,直到事务结束才释放。事务结束包括正常结束(COMMIT)和非正常结束(ROLLBACK)。
- 二级封锁协议:一级封锁协议加上事务T在读取数据R之前必须先对其加S锁,读完后方可释放S锁。
- 三级封锁协议 :一级封锁协议加上事务T在读取数据R之前必须先对其加S锁,直到事务结束才释放。
可见,三级锁操作一个比一个厉害(满足高级锁则一定满足低级锁)。但有个非常致命的地方,一级锁协议就要在第一次读加x锁,直到事务结束。几乎就要在整个事务加写锁了,效率非常低。三级封锁协议只是一个理论上的东西,实际数据库常用另一套方法来解决事务并发问题。
隔离性级别
mysql用意向锁(另一种机制)来解决事务并发问题,为了区别封锁协议,弄了一个新概念隔离性级别:包括Read Uncommitted、Read Committed、Repeatable Read、Serializable,见这篇。mysql 一般默认Repeatable Read。
终于发现自己为什么会误会事务能解决丢失修改了。至于为什么隔离性级别不解决丢失修改,我猜是有更好的解决方案吧。
总结一下,repeatable read能解决脏读和不可重复读,但不嗯呢该解决丢失修改。