Oracle数据库之事务

1. 什么是事务

在数据库中事务是工作的逻辑单元,一个事务是由一个或多个完成一组的相关行为的SQL语句组成,通过事务机制确保这一组SQL语句所作的操作要么都成功执行,完成整个工作单元操作,要么一个也不执行。

如:网上转帐就是典型的要用事务来处理,用以保证数据的一致性。

2. 事务特性

SQL92标准定义了数据库事务的四个特点:

  • 原子性(Atomicity):一个事务里面所有包含的SQL语句是一个执行整体,不可分割,要么都做,要么都不做。
  • 一致性(Consistency):事务开始时,数据库中的数据是一致的,事务结束时,数据库的数据也应该是一致的。
  • 隔离性(Isolation):是指数据库允许多个并发事务同时对其中的数据进行读写和修改的能力,隔离性可以防止事务的并发执行时,由于他们的操作命令交叉执行而导致的数据不一致状态。
  • 持久性 (Durability) : 是指当事务结束后,它对数据库中的影响是永久的,即便系统遇到故障的情况下,数据也不会丢失。

一组SQL语句操作要成为事务,数据库管理系统必须保证这组操作的原子性(Atomicity)、一致性(consistency)、隔离性(Isolation)和持久性(Durability),这就是ACID特性。

3. 数据异常

因为Oracle中支持多个事务并发执行,所以会出现下面的数据异常。

3.1 脏读

当一个事务修改数据时,另一事务读取了该数据,但是第一个事务由于某种原因取消对数据修改,使数据返回了原状态,这是第二个事务读取的数据与数据库中数据不一致,这就叫脏读。

如:事务T1修改了一条数据,但是还未提交,事务T2恰好读取到了这条修改后了的数据,此时T1将事务回滚,这个时候T2读取到的数据就是脏数据。

3.2 不可重复读

是指一个事务读取数据库中的数据后,另一个事务则更新了数据,当第一个事务再次读取其中的数据时,就会发现数据已经发生了改变,这就是不可重复读取。不可重复读取所导致的结果就是一个事务前后两次读取的数据不相同。

如:事务T1读取一行记录,紧接着事务T2修改了T1刚刚读取的记录,然后T1再次查询,发现与第一次读取的记录不同。

3.3 幻读

如果一个事务基于某个条件读取数据后,另一个事务则更新了同一个表中的数据,这时第一个事务再次读取数据时,根据搜索的条件返回了不同的行,这就是幻读。

如:事务T1读取一条指定where条件的语句,返回结果集。此时事务T2插入一行新记录,恰好满足T1的where条件。然后T1使用相同的条件再次查询,结果集中可以看到T2插入的记录,这条新纪录就是幻读。

事务中遇到的这些异常与事务的隔离性设置有关,事务的隔离性设置越多,异常就出现的越少,但并发效果就越低,事务的隔离性设置越少,异常出现的越多,并发效果越高。

4. 事务隔离级别

针对读取数据时可能产生的不一致现象,在SQL92标准中定义了4个事务的隔离级别:

隔离级别 脏读 不可重复读 幻读
Read uncommitted(读未提交)
Read committed(读已提交)
Repeatable read(可重复读)
Serializable(串行读)

Oracle默认的隔离级别是read committed。

Oracle支持上述四种隔离级别中的两种:read committed 和serializable。除此之外,Oralce中还定义Read only和Read write隔离级别。

Read only:事务中不能有任何修改数据库中数据的操作语句,是Serializable的一个子集。

Read write:它是默认设置,该选项表示在事务中可以有访问语句、修改语句,但不经常使用。

设置隔离级别

设置一个事务的隔离级别:

  • SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
  • SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
  • SET TRANSACTION READ ONLY;
  • SET TRANSACTION READ WRITE;

注意:这些语句是互斥的,不能同时设置两个或两个以上的选项。

设置单个会话的隔离级别:

  • ALTER SESSION SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
  • ALTER SESSION SET TRANSACTION ISOLATION SERIALIZABLE;

5. 事务控制命令

5.1 提交事务

在执行使用COMMIT语句可以提交事务,当执行了COMMIT语句后,会确认事务的变化,结束事务,删除保存点,释放锁。当使用COMMIT语句结束事务之后,其他会话将可以查看到事务变化后的新数据。

5.2 回滚事务

保存点(savepoint):是事务中的一点,用于取消部分事务,当结束事务时,会自动的删除该事务所定义的所有保存点。当执行ROLLBACK时,通过指定保存点可以回退到指定的点。

设置保存点:

sql> Savepoint a;

删除保存点:

sql> Release Savepoint a;

回滚部分事务:

sql> Rollback To a;

回滚全部事务:

sql> Rollback;

6. 数据库锁

数据库是一个多用户使用的共享资源。当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性。

在数据库中有两种基本的锁类型:排它锁(Exclusive Locks,即X锁)和共享锁(Share Locks,即S锁)。当数据对象被加上排它锁时,其他的事务不能对它读取和修改;加了共享锁的数据对象可以被其他事务读取,但不能修改。

6.1 锁分类

根据保护对象的不同,Oracle数据库锁可分为:

  • DML lock(data locks,数据锁):用于保护数据的完整性。
  • DDL lock(dictionary locks,字典锁):用于保护数据库对象的结构(例如表、视图、索引的结构定义)。
  • Internal locks 和latches(内部锁与闩):保护内部数据库结构。
  • Distributed locks(分布式锁):用于OPS(并行服务器)中。
  • PCM locks(并行高速缓存管理锁):用于OPS(并行服务器)中。

在Oracle中最主要的锁是DML锁,DML锁的目的在于保证并发情况下的数据完整性。在Oracle数据库中,DML锁主要包括TM锁和TX锁,其中TM锁称为表级锁,TX锁称为事务锁或行级锁。

锁出现在数据共享的场合,用来保证数据的一致性。当多个会话同时修改一个表时,需要对数据进行相应的锁定。

锁有“共享锁”、“排它锁”,“共享排它锁”等多种类型,而且每种类型又有“行级锁” (一次锁住一条记录),“页级锁” (一次锁住一页,即数据库中存储记录的最小可分配单元),“表级锁” (锁住整个表)。

6.2 共享锁(S锁)

可通过lock table in share mode命令添加该S锁。在该锁定模式下,不允许任何用户更新表。但是允许其他用户发出select …from for update命令对表添加RS锁。

6.3 排他锁(X锁)

可通过lock table in exclusive mode命令添加X锁。在该锁定模式下,其他用户不能对表进行任何的DML和DDL操作,该表上只能进行查询。

6.4 行级共享锁(RS锁)

通常是通过select … from for update语句添加的,同时该方法也是我们用来手工锁定某些记录的主要方法。比如,当我们在查询某些记录的过程中,不希望其他用户对查询的记录进行更新操作,则可以发出这样的语句。当数据使用完毕以后,直接发出rollback命令将锁定解除。当表上添加了RS锁定以后,不允许其他事务对相同的表添加排他锁,但是允许其他的事务通过DML语句或lock命令锁定相同表里的其他数据行。

6.5 行级排他锁(RX锁)

当进行DML操作时会自动在被更新的表上添加RX锁,或者也可以通过执行lock命令显式的在表上添加RX锁。在该锁定模式下,允许其他的事务通过DML语句修改相同表里的其他数据行,或通过lock命令对相同表添加RX锁定,但是不允许其他事务对相同的表添加排他锁(X锁)。

6.6 共享行级排他锁(SRX锁)

通过lock table in share row exclusive mode命令添加SRX锁。该锁定模式比行级排他锁和共享锁的级别都要高,这时不能对相同的表进行DML操作,也不能添加共享锁。

上述几种锁模式中,RS锁是限制最少的锁,X锁是限制最多的锁。它们的兼容关系如下:

基本上所有的锁都可以由Oracle内部自动创建和释放,但是其中的DDL和DML锁是可以通过命令进行管理的,命令语法:

LOCK table_name IN
[row share][row exclusive][share][share row exclusive][exclusive] MODE
[NOWAIT];

下图列出产生锁定模式的SQL语句:

当程序对所做的修改进行提交(Commit)或回滚(Rollback)后,锁住的资源便会得到释放,从而允许其他用户进行操作。如果两个事务,分别锁定一部分数据,而都在等待对方释放锁才能完成事务操作,这种情况下就会发生死锁

7. 数据库事务实现机制

几乎所有的数据库管理系统中,事务管理的机制都是通过使用日志文件来实现的,我们来简单介绍一下日志的工作方式。

当用户执行一条修改数据库的DML语句时,DBMS自动在日志文件中写一条记录,显示被这条语句影响的每一条记录的两个副本。一个副本显示变化前的记录,另一个副本显示变化后的记录。当日志写完之后,DBMS才实际对磁盘中的记录进行修改。

如果用户随后执行COMMIT语句,事务结束也被记录在事务日志中。如果用户执行ROLLBACK语句,DBMS检查日志,找出自事务开始以来被修改的记录“以前”的样子,然后使用这些信息恢复它们以前的状态,有效地撤销事务期间对数据库所做的修改。

如果系统出错,系统操作员通常通过运行DBMS提供的特殊恢复程序来复原数据库。恢复程序检查到事务日志末尾,查找故障之前没有被提交的事务。恢复程序回滚没有完全完成的事务,以便仅有被提交的事务反映到数据库中,而故障中正处理的事务被回滚。

事务日志的使用明显增加了更新数据库的开销。在实际中,主流商用DBMS产品使用的日志技术比上述描述的方案更复杂,用以减小这种开销。此外,事务日志通常被存储在高速磁盘驱动器中,不同于存储数据库的磁盘,以减小磁盘访问竞争。某些个人计算机DBMS产品允许关闭事务日志性能,以提高DBMS的性能。

8. 示例

银行转帐的例子是最经典的事务示例:

用户把钱从一个银行账号转账至另一个银行账号,需要将资金从一个银行账号中取出,然后再存入另一个银行账号中。理想来说,这两次操作都应该成功。但是,如果有错误发生,则两次操作都应该失败,否则的话,操作之后其中一个账号中的金额将会是错误的,整个操作过程应该是原子性的,两个操作都是一个原子事务操作的一部分。

示例:

-- 从账户一向账户二转账
DECLARE
v_money NUMBER(8, 2); -- 转账金额
v_balance account.balance%TYPE; -- 账户余额
BEGIN
v_money := &转账金额; -- 输入转账金额
-- 从账户一减钱
UPDATE account SET balance = balance - v_money WHERE id=&转出账户
RETURNING balance INTO v_balance;
IF SQL%NOTFOUND THEN
RAISE_APPLICATION_ERROR(-20001, '没有该账户:'||&转出账户);
END IF;
IF v_balance < 0 THEN
RAISE_APPLICATION_ERROR(-20002, '账户余额不足');
END IF; -- 向账户二加钱
UPDATE account SET balance = balance + v_money WHERE id=&转入账户;
IF SQL%NOTFOUND THEN
RAISE_APPLICATION_ERROR(-20001, '没有该账户:'||&转入账户);
END IF; -- 如果没有异常,则提交事务
COMMIT;
DBMS_OUTPUT.PUT_LINE('转账成功'); EXCEPTION
WHEN OTHERS THEN
ROLLBACK; -- 出现异常则回滚事务
DBMS_OUTPUT.PUT_LINE('转账失败:');
DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;

Oracle数据库之事务的更多相关文章

  1. 小菜鸟之Oracle数据库之事务

    Oracle数据库之事务 1. 什么是事务 在数据库中事务是工作的逻辑单元,一个事务是由一个或多个完成一组的相关行为的SQL语句组成,通过事务机制确保这一组SQL语句所作的操作要么都成功执行,完成整个 ...

  2. Oracle数据库只读事务和无事务的区别

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt382 Oracle默认情况下(没有事务) 保证了SQL语句级别的读一致性,即 ...

  3. 2018.6.24 oracle数据库的 事务及视图

    第06章 事务及视图 本章内容  事务  视图 1 事务 1.1 什么是事务 事务也称工作单元,是一个或多个SQL语句组成的序列,这些个SQL操作作为一个完整的工作单元要么全部执行,要么全不执行. ...

  4. 【Oracle】浅析Oracle中的事务

    1. 什么是事务 在数据库中事务是工作的逻辑单元,一个事务是由一个或多个完成一组的相关行为的SQL语句组成,通过事务机制确保这一组SQL语句所作的操作要么都成功执行,完成整个工作单元操作,要么一个也不 ...

  5. Oracle数据库体系结构(3)数据库进程

    一.Oracle进程概述 在oracle中进程分为用户进程(User Process).服务器进程(server process)和后天进程3种. 1.用户进程:当用户连接到数据库执行一个应用程序是, ...

  6. 数据库事务隔离级ORACLE数据库事务隔离级别介绍

    本文系转载,原文地址:http://singo107.iteye.com/blog/1175084 数据库事务的隔离级别有4个,由低到高依次为Read uncommitted.Read committ ...

  7. ORACLE数据库事务隔离级别

    转自:https://www.cnblogs.com/jackal/archive/2011/02/14/1954231.html 事务隔离级别:一个事务对数据库的修改与并行的另一个事务的隔离程度. ...

  8. C# 连接 Oracle数据库增删改查,事务

    一. 前情提要 一般.NET环境连接Oracle数据库,是通过 TNS/SQL.NET 配置文件,而 TNS 必须要 Oracle 客户端(如果连接的是服务器的数据库,本地还要装一个 client , ...

  9. Oracle 数据库语句大全

    Oracle数据库语句大全 ORACLE支持五种类型的完整性约束 NOT NULL (非空)--防止NULL值进入指定的列,在单列基础上定义,默认情况下,ORACLE允许在任何列中有NULL值. CH ...

随机推荐

  1. android手机游戏开发Cocos2d-x开发分享

    我想现在应该没有人没有玩过手机游戏了吧,当然所有人都玩过,但不是所有人都知道怎么去开发手机游戏,因为许多人都感觉做开发是一件很困难的事儿,身边的朋友也对此感觉难度很大.但是,现在我可以告诉你,手机游戏 ...

  2. BZOJ 1007 [HNOI2008]水平可见直线

    1007: [HNOI2008]水平可见直线 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 4453  Solved: 1636[Submit][Sta ...

  3. 第2个Wiindows程序讲解

    上次,我们一起写了一个Windows窗口程序,这个窗口程序虽然非常简单,但是,代码仍然很多,相信,一定会有很多初学者看见这些代码而感到头疼.不用怕,现在,我们就一起来分析一下这些代码,相信通过我们共同 ...

  4. Sum Root to Leaf Numbers——LeetCode

    Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number ...

  5. DLL入门浅析(3)——从DLL中导出变量

    转载自:http://www.cppblog.com/suiaiguo/archive/2009/07/20/90643.html 前面介绍了怎么从DLL中导出函数,下面我们来看一下如何从DLL中导出 ...

  6. [Design Pattern] Singleton Pattern 简单案例

    Singleton Pattern, 即单例模式,用于获取类的一个对象,该对象在整个应用中是其类的唯一对象.单例模式属于创建类的设计模式. SingleObject 作为单例类,内含了一个静态私有的 ...

  7. [TCO 2012 Round 3A Level3] CowsMooing (数论,中国剩余定理,同余方程)

    题目:http://community.topcoder.com/stat?c=problem_statement&pm=12083 这道题还是挺耐想的(至少对我来说是这样).开始时我只会60 ...

  8. php显示日期(今天、昨天、本周、上周、本月、上月、)

    <?php //今天 $today = date("Y-m-d"); //昨天 $yesterday = date("Y-m-d", strtotime( ...

  9. 解决hyerv的linux虚拟机网卡地址重启发生变化的问题

    关于linux的虚拟机,当进行虚拟机copy的时候,由于虚拟机配置文件里面会记录网卡的mac地址,所以导致linux里面记录的网卡地址和实际的会有冲突,这样linux会自动把网卡地址提高. 比如原来是 ...

  10. 使用PHPExcel导出数据

    最近要求做增加客流数据等导出为Excel的功能,phpExcel包功能强大,根据实际需求,我只学习了简单的功能. 安装PHPExcel 在composer.json中添加: "require ...