做网站用什么地图好,做网页要多少钱,网站收录下降原因,网页制作工具按其制作方式有几种类型什么是事务
事务是数据库管理系统执行过程的一个逻辑单位#xff0c;由一系列有限的数据库操作序列构成#xff0c;事务必须满足ACID属性。ACID理论是数据库中最重要的概念之一#xff0c;分别代表原子性#xff08;Atomicity#xff09;、一致性#xff08;Consisten…什么是事务
事务是数据库管理系统执行过程的一个逻辑单位由一系列有限的数据库操作序列构成事务必须满足ACID属性。ACID理论是数据库中最重要的概念之一分别代表原子性Atomicity、一致性Consistency、隔离性Isolation和持久性Durability。
原子性是指事务是一个不可分割的工作单位事务中的操作要么都发生要么都不发生一致性是指事务将数据库从一个一致的状态转移到另一个一致的状态这意味着事务执行的结果必须符合所有预定义的规则和约束隔离性是多个用户并发访问数据库时数据库为每一个用户开启的事务不能被其他事务的操作数据所干扰多个并发事务之间要相互隔离持久性是指一个事务一旦被提交它对数据库中数据的改变就是永久性的接下来即使数据库发生故障也不应该对其有任何影响。
最经典的事务就是银行转账的例子小明从自己的账户往小红账户汇款1000元对应数据库的操作如下。
update account set balance balance - 1000 where name xiaoming;
update account set balance balance 1000 where name xiaohong;如果只是第一条语句正常执行小明白白损失1000元肯定要找银行的麻烦如果第一条失败第二条正常执行银行白白损失1000元长此以往估计要破产。所以看似简单的两条语句执行起来却需要遵循ACID特性来保证数据的一致性。
关系型数据库普遍支持事务Oracle是一个强一致性的关系型数据库设计上严格遵守了事务ACID特性。那么Oracle数据库有哪些设计来实现事务的ACID呢
事务隔离性与隔离级别
事务是由多个原子操作组合而成因此会出现中间状态。比如前面转账的例子当执行完第一条语句后因为某种原因没有继续往下执行而是暂停了程序(注意事务并没有结束)。第二个会话去查询时会发现账户余额仍然是1500并没有发生改变。
## session 1
## 假设更新之前账户余额为1500
update account set balance balance - 1000 where name xiaoming;## session 2
## 第二个会话查询结果仍然是1500
select balance from account where name xiaoming;当数据库上有多个事务并发执行的时候不同事务之间会产生相互影响上面的例子中两个会话操作的是同一个账户的数据当会话1事务没结束之前会话2返回了会话1修改之前的数据。那会话2查询到的数据是正确的吗这个其实是事务隔离性的一种体现在数据库概念中有个专门的名词叫“隔离级别”。
根据各种可能的场景SQL标准的隔离级别被定义为四种类型读未提交(Read Uncommitted)、读提交(Read Committed)、可重复读(Repeatable Read)和串行化(Serializable)。
隔离级别定义优点缺点读未提交一个事务还没提交时它所做的变更就能被其他事务看到事务之间没有任何隔离并发度好如果未提交的数据时候回滚读取将是无效的产生“脏读”读已提交一个事务提交之后它所做的变更才能被其他事务看到常见的隔离级别比较符合业务逻辑需求同一个事务多次查询可能得到不同的结果产生“幻读”可重复读一个事务执行过程中看到的数据总是和这个事务在启动时看到的数据一致常见的隔离级别避免产生“幻读”有一定的应用场景隔离代价更高对应用并发执行有一定的影响串行化在上一个事务未提交之前任何其他的事务都不能访问这个数据事务之间完全隔离应用不能并发访问对性能有严重的影响
为了便于大家的理解我把四种类型的隔离级别的定义及优缺点用表格的方式呈现出来相信大家已经看出来了四种隔离级别是层层递进的越往后隔离程度越高对并发访问的影响也越大。简单来说隔离程度越高效率就越低因此我们需要在二者之间寻找一个平衡点。
不同的数据库有自己默认的隔离级别在Oracle中默认是“读已提交”也就是说在一个事务没有提交之前其他会话看不到数据变化的中间状态。所以上面银行转账的例子如果继续执行下去我们会得到以下的结果。
时间点会话1会话209:00:00xiaoming账户转出1000元余额500元09:00:01查询xiaoming账户余额仍为1500元09:00:02提交事务09:00:03查询xiaoming账户余额为500元
会话2两次查询结果不一样就是我们所说的“幻读”这可能会对我们的业务处理造成一定的困扰。比如有两张表分别是账户余额和交易明细月底数据核对的时候如果有用户触发了新的交易可能会让你两次查询得到不同的结果影响你的核对工作。
为了避免“幻读”现象也有一些数据库比如MySQL数据库默认隔离级别是可重复读“上面的例子在MySQL默认隔离级别下的表现是这样的。
时间点会话1会话209:00:00xiaoming账户转出1000元余额500元开启事务09:00:01查询xiaoming账户余额仍为1500元09:00:02提交事务09:00:03查询xiaoming账户余额仍为1500元09:00:04提交事务09:00:05查询xiaoming账户余额为500元
这次会话2的事务提交之前查询的结果始终没有发生变化避免了“幻读”的发生。因此在MySQL和Oracle之间的迁移需要注意数据库默认的隔离级别相同的应用程序可能跑出来不同的结果。
此外也需要提醒大家的是为了提升一个隔离级别衍生出来一系列的加锁操作增加了实现的难度对应用的并发也有一定的影响。
Oracle隔离性的实现
多版本并发控制Multi-Version Concurrency Control, MVCC是一种用于提高数据库并发性能的技术在早先的Oracle时代却很少有人提及。事实上早在Oracle 8i的时代就支持MVCC技术其实现方式是在数据库中引入Undo表空间通过Undo来构造一致性读以此来实现并发事务之间的数据隔离。
在《Oracle日志系统一条SQL更新语句是如何执行的》这篇文章中介绍数据更新时提到了“前镜像”这个前镜像的数据就保存在Undo表空间。事务开始时会在Undo表空间中分配一个Undo段当数据发生改变时原始值会被拷贝到Undo段。当有会话读取到未提交的数据时会通过链接指向Undo段读取Undo段中的“前镜像”值。早期的数据库中Oracle有一项非常傲人的特性 – 读永远都不会被阻塞就是通过Undo来实现的。
但是Undo表空间也是有限的Undo段中的数据不可能永久保留。那么什么时候其中的数据才可以被覆盖呢答案是最少要保留到事务的正常结束。但如果仅仅保留到事务结束是否够用呢我们看看下面的场景。
时间点会话1会话209:00:00开启事务更新表A数据09:01:00查询表A数据09:05:00提交事务09:30:00查询结束
会话1在09:00开始事务09:05结束事务。同时会话2在09:01开始一个新的查询但是这个查询执行了29分钟直到09:30才结束如果在09:30之前和表A相关的Undo数据被清理会话2就会报出ORA-01555的错误。这是在早期Oracle数据库中非常经典的错误触发错误的原因就是会话需要读取Undo数据但已经被清理。
由于所保存数据的特殊性Undo表空间的管理上和其他表空的区别很大限于篇幅的原因我们在后面有专门的章节详细讲解。
事务的开始和结束
事务由事务开始与事务结束之间执行的全部数据库操作构成这些操作要么全部成功要么全部失败必须以一个整体面向数据库这就是事务的原子性。
不同事务的开始和结束标志有所差别Oracle数据库事务的开始通常有两种方式
以DML语句开始表示一个事务的开始这种也称为隐式事务开始以关键字BEGIN表示事务的开始这种也称为显示事务开始。
事务的结束有三种方式
以关键字COMMIT或ROLLBACK表示事务的结束这种称为显示事务结束。如果事务以COMMIT结束则意味着数据更新被确认更新后的数据将最终会被写入到磁盘中如果事务以ROLLBACK结束则意味着放弃本次更新操作所有在这个事务中的操作都会回滚到更新之前的状态会话正常退出比如执行某个DML操作后执行exit退出会话这个操作包含隐式的COMMIT之前的操作会被保存更新会话异常退出比如会话进程被kill这个则意味着隐式的ROLLBACK所有的操作会回滚到更新之前的状态。
总结
这篇文章中我们给大家介绍了Oracle数据库事务隔离的原理和实现通过引入Undo段构造“前镜像”Oracle实现了在Read Committed级别下的事务隔离。
由于Undo数据的特殊性其管理上和其他表空间的差别也很大大家遇到过哪些Undo相关的错误又是如何解决的呢