文章目录
1 概述
1.1 事务的特性 ACID
事务特性 | 描述 |
---|---|
原子性(Atomicity) | 原子工作单元,不可分割 |
一致性(Consistency) | 事务结束前后,数据 整体不变 |
隔离性(Isolation) | 多个事务独立运行,互不干扰 |
持久性(Durability) | 事务一旦提交,对数据的改变 永久有效 |
举例:【银行转账】张三 向 李四 银行转账 100 元
-- 步骤1:张三 的账户金额 - 100 元
update account
set money = money - 100
where name = '张三';
-- 步骤2:李四 的账户金额 + 100 元
update account
set money = money + 100
where name = '李四';
-- 特性解释:
原子性:上述 2 条 sql 语句的执行,要么全部成功,要么全部失败
一致性:账户总金额不变
隔离性:张三、李四 看不到彼此的账户信息
持久性:事务提交后,账户金额被永久保存
1.2 事务的状态
事务进入中止状态后,系统一般有如下两种选择:
① 重启事务
② 杀死事务
2 并发
事务的并发控制,可能会带来如下问题
问题 | 描述 |
---|---|
脏读 | 事务A 读到了 事务B 修改但未提交 的数据 |
幻读 | 在同一事务中,两次读取同一数据,得到的记录行数不同 |
不可重复读 | 在同一事务中,两次读取同一数据,得到的数据内容不同 |
-- 基础数据准备
create table scott.emp_bak as select * from scott.emp;
-- 查询基础数据
select * from scott.emp_bak;
2.1 脏读 Dirty Read
描述:假如 事务B 回退,则 事务A 读取的是 “无效” 的数据(“脏数据”)
事务A 事务B
----------------------------------------------------
update scott.emp_bak t2
set t2.job = 'TEST'
where t2.empno = 7369;
----------------------------------------------------
select t1.job -- Test
from scott.emp_bak t1
where t1.empno = 7369;
----------------------------------------------------
rollback;
2.2 幻读 Phantom Read
描述:事务A 两次读取 事务B 的记录行数不一样,感觉发生了 “幻觉”
注意:侧重 记录行数 不一样,如:insert、delete 操作
事务A 事务B
----------------------------------------------------
select t1.job
from scott.emp_bak t1
where t1.empno = 7369;
----------------------------------------------------
insert into scott.emp_bak(empno, job)
values(7369, 'Test2');
commit;
----------------------------------------------------
select t1.job -- 多了 Test2
from scott.emp_bak t1
where t1.empno = 7369;
2.3 不可重复读 Nonrepeatable Read
描述:事务A 两次读取 事务B 的数据内容不一样
注意:侧重 数据内容 不一样,如:update 操作
事务A 事务B
----------------------------------------------------
select t1.job
from scott.emp_bak t1
where t1.empno = 7369;
----------------------------------------------------
update scott.emp_bak t2
set t2.job = 'Test2'
where t2.empno = 7369;
commit;
----------------------------------------------------
select t1.job -- 变成了 Test2
from scott.emp_bak t1
where t1.empno = 7369;
3 隔离
3.1 隔离级别
隔离级别(由低到高) | 脏读 | 不可重复读 | 幻读 | 数据库默认 |
---|---|---|---|---|
读未提交 (Read Uncommitted) | √ | √ | √ | |
读已提交 (Read Commited) | × | √ | √ | Oracle |
重复读取(Repeatable Read) | × | × | √ | Mysql |
序列化 (Serializable) | × | × | × |
说明:
- 引入事务隔离级别的目的:解决 事务的并发问题
- 隔离级别并非越高越好。越高意味着需要更多的 锁 来保证事务的正确性,效率就越低
3.2 查询和设置
-- 1. 首先创建一个事务(若有,可忽略)
declare
trans_id varchar2(100);
begin
trans_id := dbms_transaction.local_transaction_id(true);
end;
-- 2. 查询 事务隔离级别
select (case bitand(t.flag, power(2, 28))
when 0 then
'READ COMMITTED'
else
'SERIALIZABLE'
end) 事务隔离级别,
s.username,
s.sid,
s.serial#,
s.*
from v$transaction t,
v$session s
where s.taddr = t.addr;
-- 3. 设置 事务隔离级别 (Oracle 仅支持以下两种)
set transaction isolation level [read committed | serializable];