事务:代表一个业务边界(业务逻辑的多条语句组成)
比如:博客管理系统(用户实体,板块实体,主贴实体,回帖实体)回帖业务
1、用户向回帖表中插入一条记录
INSERT INTO REPLY VALUES ....
2、回帖用户积分+3
UPDATE USER SET SCORE = SCORE + 3 WHERE USERNAME = '回帖用户';
3、发帖用户积分+5
UPDATE USER SET SCORE = SCORE + 5 WHERE USERNAME = '发帖用户';
上述三个步骤(语句)是一个业务整体
事务的特性 ACID
- 原子性(Atomicity):事务是一个整体的工作单元,事务对数据库所做的操作要么全部执行,要么全部取消。如果某条语句执行失败,则所有语句全部回滚。
- 一致性(Consistency):事务在完成时,必须使所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。如果事务成功,则所有数据将变为一个新的状态;如果事务失败,则所有数据将处于开始之前的状态。
- 隔离性(Isolation):事务与事务之间是相互隔离的
由事务所作的修改必须与其他事务所作的修改隔离。事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。
- 持久性(Durability):事务提交后,对数据库数据的影响是持久性(永久的)
事务的操作
- 事务提交 COMMIT;
- 事务回滚 ROLLBACK
- 事务保存点 SAVEPOINT
- 执行一条数据定义语句,比如,CREATE、DROP或ALTER等语句。如果该语句执行成功,那么Oracle系统会自动执行COMMIT命令;否则,则Oracle系统会自动执行ROLLBACK命令。
- 执行一个数据控制命令,比如,GRANT、REVOKE等控制命令,这种操作执行完毕,Oracle系统会自动执行COMMIT命令。
- 正常地断开数据库的连接、正常地退出SQL*Plus环境,则Oracle系统会自动执行COMMIT命令;否则,则Oracle系统会自动执行ROLLBACK命令。
-- 创建一个账号表
CREATE TABLE ACCOUNT(
ACC_ID INT PRIMARY KEY,
ACC_NAME VARCHAR2(20),
ACC_BALANCE NUMBER(10,2) CONSTRAINT CK_ACCOUNT_BALANCE CHECK(ACC_BALANCE >= 0) --账户余额不能小于0
);
-- 插入两条测试数据
INSERT INTO ACCOUNT VALUES (10,'PEPPA',1000);
INSERT INTO ACCOUNT VALUES (20,'SUZY',1000);
-- 提交事务
COMMIT;
SELECT * FROM ACCOUNT;
-- 转账操作
DECLARE
BALANCEEXCEPTION EXCEPTION;
PRAGMA EXCEPTION_INIT(BALANCEEXCEPTION,-02290);
v_money number(10,2) := 500;
BEGIN
UPDATE ACCOUNT SET ACC_BALANCE = ACC_BALANCE + v_money WHERE ACC_NAME='SUZY';
UPDATE ACCOUNT SET ACC_BALANCE = ACC_BALANCE - v_money WHERE ACC_NAME='PEPPA';
-- 如果没有异常,转账成功,提交事务
COMMIT;
EXCEPTION -- 自定义异常发生,转账失败,回滚事务
WHEN BALANCEEXCEPTION THEN
DBMS_OUTPUT.put_line('转账失败');
ROLLBACK;
END;
-- 事务保存点
DECLARE
BALANCEEXCEPTION EXCEPTION;
PRAGMA EXCEPTION_INIT(BALANCEEXCEPTION,-02290);
v_money number(10,2) := 5000;
BEGIN
INSERT INTO ACCOUNT VALUES (30,'EMILY',1000);
INSERT INTO ACCOUNT VALUES (40,'PEDRO',1000);
-- 定义一个事务保存点(保存点可以定义多个)
SAVEPOINT INSERT_POINT;
-- 再次转账
UPDATE ACCOUNT SET ACC_BALANCE = ACC_BALANCE + v_money WHERE ACC_NAME='SUZY';
UPDATE ACCOUNT SET ACC_BALANCE = ACC_BALANCE - v_money WHERE ACC_NAME='PEPPA';
-- 如果没有异常,转账成功,提交事务
COMMIT;
EXCEPTION
WHEN BALANCEEXCEPTION THEN
DBMS_OUTPUT.put_line('转账失败');
-- 回滚事务到指定保存点
ROLLBACK TO INSERT_POINT;
-- 提交其它业务操作(保存点之前的业务)
COMMIT;
END;