数据库事务处理
什么是事务
事务就是业务上的一个逻辑单元,它能够保证其中对数据所有的操作,要么全部成功,要么失败。
事务控制语句
COMMIR:提交事务,即把事务中对数据库的修改进行永久保存。
ROLLBACK:回滚事务,即取消对数据库所做的任何修改。
SAVEPOINT:在事务中创建存储点。
ROLLBACKE TO<Savepoin_Name>:将事务回滚到存储点 。
SET TRANSACTION:设置事务的属性。
事务的特性(事务必须具备以下四个属性,简称ACID属性)
1.原子性(Atomicity):事务是一个完整的操作。事务的各步操作是密不可分的
(原子的):要么都执行,要么都不执行。
2.一致性(Consistency):在事务操作前后,数据必须处于一致状态。
3.隔离性(Isolation):对数据进行修改的所有并发事务是彼此隔离的,这表明事务必须是独立的,它不应以任何方式依赖于或影响其他事务。
4.持久性(Durability):事务完成后,它对数据库的修改被永久保持。
示例(原子性)
BEGIN UPDATE topic7_account SET account_balance=account_balance-5000 WHERE account_id=1001; --第一个账户取款5000 UPDATE topic7_account SET account_balance=account_balance+5000 WHERE account_id=1002; --第二个账户取款5000 COMMIT;--提交事务 EXCEPTION --异常处理 WHEN OTHERS THEN dbms_output.put_line('转账异常,停止转账');--当余额不足时执行 ROLLBACK;--回滚事务 END;
示例(一致性)
--一致性 DECLARE account_a topic7_account.account_balance%TYPE;--定义接收账户A的余额变量 account_b topic7_account.account_balance%TYPE;--定义接收账户B的余额变量 BEGIN SELECT account_balance INTO account_a FROM topic7_account WHERE account_id=1001;--接收账户A的余额 SELECT account_balance INTO account_b FROM topic7_account WHERE account_id=1002; --接收账户B的余额 dbms_output.put_line('转账前账户A的余额'||account_a); dbms_output.put_line('转账前账户B的余额'||account_b); dbms_output.put_line('转账前两个账户的总余额'||(account_a+account_b)); --输出两个账户的总额 UPDATE topic7_account SET account_balance=account_balance-2000 WHERE--账户A转出2000,更新数据 account_id=1001; UPDATE topic7_account SET account_balance=account_balance+2000 WHERE--账户B转入2000,更新数据 account_id=1002; COMMIT; SELECT account_balance INTO account_a FROM topic7_account WHERE account_id=1001; SELECT account_balance INTO account_b FROM topic7_account WHERE account_id=1002; dbms_output.put_line('转账后账户A的余额'||account_a); dbms_output.put_line('转账后账户B的余额'||account_b); dbms_output.put_line('转账后两个账户的总余额'||(account_a+account_b)); EXCEPTION--当产生异常情况 WHEN OTHERS THEN dbms_output.put_line('转账错误停止转账'); ROLLBACK;--回滚,恢复没转账前的状态 SELECT account_balance INTO account_a FROM topic7_account WHERE account_id=1001; SELECT account_balance INTO account_b FROM topic7_account WHERE account_id=1002; dbms_output.put_line('停止转账后账户A的余额'||account_a); dbms_output.put_line('停止转账后账户B的余额'||account_b); dbms_output.put_line('停止转账后两个账户的总余额'||(account_a+account_b)); END;
隔离性:事务隔离性要求:在事务的处理过程中,其他事务不能访问该事务中的数据。
事务A:
--账户A修改了数据但未提交 UPDATE topic7_account SET account_balance=account_balance+2000 WHERE account_id=1001; UPDATE topic7_account SET account_balance=account_balance+2000 WHERE account_id=1002;
事务B:
--事务B也对数据 进行修改 UPDATE topic7_account SET account_balance=account_balance+3000 WHERE account_id=1001;
在这一过程中事务B读取不了正在修改过程的事务A中的数据但是可以得到数据处理前的数据或处理后的数据,体现了隔离性。
事务与事务间都是相对独立的。
读取异常:
脏读:一个事务读取了另一个事务未提及的数据(指一个事务修改了该数据但未提交的情况下,另一个事务也访问了该数据,返回的数据可能存在误差,比如读读取的是事务修改前的数据,而后再次得到的是数据已提交的数据)。
不可重复读:一个 事务读取数据后,然后再次对同一个数据进行读取,期间发现该数据已经被另一个事务修改,导致前后读取的数据不一致。
幻读:一个事务根据相同的查询条件,重新执行查询,返回的记录包含前一次执行查询返回的记录不同行。
ANSI SQL-92标准中定义的事务隔离级别
Read Uncommitted
最低等级的事务隔离,它仅仅保证了读取过程中不会读取到非法数据。
Read Committed
此级别的事务隔离保证了一个书屋不会读取到另一个并行事务已修改但未提交的数据,也就是说,此等级的事务级别避免了“脏读”。
Repeatable Read
此等级的事务隔离避免了“脏读”和 “不可重复读”异常现象的出现。这也意味着,一个事务不可能更新已经由另一个事务读取但未提交的数据。(应用不广泛,带来性能损耗)
Serializable
最高等级的隔离级别,提供了最高等级的隔离机制,三种异常情况都能避免。
SAVEPOINT:在事务中创建存储点
语法:
SAVEPOINT[SAVEPOINT_NAME]
ROLLBACK TO<SAVEPOINT_NAME>:将事务回滚到存储点
BEGIN UPDATE topic7_account SET account_balance=account_balance+2000 WHERE account_id=1001; SAVEPOINT add_save;--存储点 UPDATE topic7_account SET account_balance=account_balance-1000 WHERE account_id=1001; UPDATE topic7_account SET account_balance=account_balance+1000 WHERE account_id=1002; EXCEPTION WHEN OTHERS THEN dbms_output.put_line('转账异常,停止转账'); ROLLBACK TO add_save; --回滚存储点 END;
SET TRANSACTION:设置事务的属性
SET TRANSACTION语句的第一条语句
制定事务的隔离级别
规定回滚事务时所使用的存储空间
对事物命名
设置隔离级别的语法
SET TRANSACTION READ ONLY;(只读情况)
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;(避免脏读异常)
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;(避免脏读,不可重复读 ,幻读异常)