数据库是一个并发访问的系统,所以说对一个数据库来说最大的问题就是并发控制的问题,这个并发控制所表现的不是在并发读上面,而是在并发写上面。对应并发写,就需要保证数据的一致性!那么什么是是数据一致性呢? 先看看什么是数据的不一致性。
数据不一致性:
脏读
张三的存款是1000,早上10点某个做了一个update 变成10000 update xxx set money=10000 where xx 但是没有提交,10点过1分的时候张三去查发现他的钱变成了10000了,这个就是脏读,因为张三读取的是没有提交的数据
不可重复读取:
张三 700
。。。
。。。
李四 1000
在10点的时候有一个人发出了一个select * from t;的sql 先读取了张三700的这个记录, 10点过1分查询还在进行,这个时候有个用户做了一个转账,把从李四的卡里面转了300给张三,当用户读取到李四这个记录的时候,如果返回的结果是700,那么就是一个不可重复读
幻影读
10点发起了一个全表扫描,10点过1分的时候查询还在进行,然后在10点过2分insert了一条记录为vic,那么查询到这个记录的时候是否会读取,如果读取了那就是是一个幻影读
维护这几种数据库一致性oracle都是通过undo的方式去实现的
一致性的另外一个情况,如果说有两个用户同时想修改表中的一行怎么办??
测试:
锁的特点:
自动管理
伴随整个事物
锁的种类:
1、DML锁
在对数据进行修改的时候就会产生DML锁,一个事务会产生两把锁,一个是行级别的TX锁,一个是表级别的表级共享锁
为什么要有TX和TM的存在呢?
select sid,TYPE,ID1,ID2,LMODE,REQUEST,CTIME from v$lock; --发起dml,使用语句查询
TX(行级别)
保护事务中某一行的一致性
TM(表级别)
尝试drop table;
2、DDL锁
3、LATCH
队列机制,先进先出,一个个的排队
DML锁
TX锁:
通过一个具体的sql,去理解DML锁
用户发出 update emp set sal=100 where empno=7369;
1、找到empno=7369这行的位置,比如说在100号块上面
2、分配undo数据块,并且把7369这个人原来的sal的值放入到undo上面
3、在数据块上分配一个ITI槽,记录事务id,undo的地址,scn,状态(是否提交)等信息
4、找到empno=7369这行的记录,在行头设定锁标记,记录当前事务的iti号
5、把控制全交给用户
在第四步 行头的时候就是一个TX锁。
问题:
如果需要跟新的不是一行记录呢??where deptno=10?? 会有几个TX锁?
因为这三条记录是属于同一个事物的的,tx是叫事物排它锁。
测试:
SQL> update emp set sal=100 where empno=7369; --有几个TX锁、几个TM锁
1 row updated.
SQL>
SQL>
SQL>
SQL> update emp set sal=10 where deptno=30; --有几个TX锁、几个TM锁
6 rows updated.
SQL>
SQL> update dept set loc='GZ' where deptno=10;--有几个TX锁、几个TM锁
1 row updated.
v$lock
ADDR 锁对象的地址
KADDR
SID
TYPE 锁类型
ID1 锁标示
ID2 锁标示
LMODE 锁模式 下面会将到
REQUEST 要求得到什么样的锁模式,0表示不要求
CTIME
BLOCK
一个个的介绍这里面的字段
TX锁、TM锁中ID1,ID2的含义
为TM锁时候,ID1表示被锁定的对象的OBJECT_ID,ID2此时为“0”。
TX锁的时候 ID1对应视图V$TRANSACTION中的XIDUSN字段(Undo segment number:事务对应的撤销段序列号)和XIDSLOT字段(Slot number:事务对应的槽位号)。其中ID1的高16位为XIDUSN,低16位为XIDSLOT。
查看高16位对应的值:
select trunc(131076/power(2,16)) XIDUSN from dual;
查看低16位对应的值:
select bitand(131076,to_number('ffff','xxxx'))+0 XIDSLOT from dual;
16为这个东西。。。 不用管
v$transaction
每一个事务在v$transaction里面有个记录
XIDUSN:就是事务的回滚段号
XIDSLOT:就是ITL列表中,slot的号
XIDSQN:就是表示这个slot被重复使用的次数
对lock来说,使用的是先到先得的机制,会有一个锁队列去控制
测试:
session 1 update dept set loc='GZ' where deptno=10;
session 2 update dept set loc='BJ' where deptno=10;
session 3 update dept set loc='SZ' where deptno=10;
select sid,TYPE,ID1,ID2,LMODE,REQUEST,CTIME from v$lock where type in ('TM','TX');
当session 1释放锁的时候,session2 和session 3谁先会获取到锁资源??
TM 锁
锁模式 锁描述 解释 SQL操作
0 none
1 NULL 空 Select
2 SS(Row-S) 行级共享锁,其他对象只能查询这些数据行 、Lock for update、Lock row share
3 SX(Row-X) 行级排它锁,在提交前不允许做DML操作 Insert、Update、Delete、Lock row share
4 S(Share) 共享锁 Create index、Lock share
5 SSX(S/Row-X) 共享行级排它锁 Lock share row exclusive
6 X(Exclusive) 排它锁 Alter table、Drop table、Drop index、Truncate table 、Lock exclusive
alter table t move;
insert into t values xxxx;
手工锁定表:没有理由不要这样做
LOCK TABLE emp in ROW SHARE mode;
LOCK TABLE emp in ROW EXCLUSIVE mode;
LOCK TABLE emp in SHARE mode;
LOCK TABLE emp in SHARE ROW EXCLUSIVE mode;
LOCK TABLE emp in EXCLUSIVE mode;
可以用这个测试一下其它的锁冲突
========================================
DDL锁
在DDL语句时产生的锁
排他DDL锁
drop table
alter table
share DDL锁
create procure 里面有很多对象,会在对应的对象上加一个共享的DDL锁,共享锁的目的是为了防止别人获得排他性的锁
死锁:
session 1
update scott.emp set sal=1 where empno=7369;
session 2
update scott.emp set sal=1 where empno=7499;
这个时候session 1 想更新7499
session 1
update scott.emp set sal=1 where empno=7499; --被hang住,啥都动不了
如果session2再去update 7369呢?
session 2
update scott.emp set sal=1 where empno=7369; --理论上也会被hang住,7369被session1获取,要等session1,但是session1要更新7499,由于被session2阻塞,啥都动不了,session2去等一个啥都动不了的session 结果就是永远等待,oracle发现这个问题会自动打破这个死锁
数据不一致性:
脏读
张三的存款是1000,早上10点某个做了一个update 变成10000 update xxx set money=10000 where xx 但是没有提交,10点过1分的时候张三去查发现他的钱变成了10000了,这个就是脏读,因为张三读取的是没有提交的数据
不可重复读取:
张三 700
。。。
。。。
李四 1000
在10点的时候有一个人发出了一个select * from t;的sql 先读取了张三700的这个记录, 10点过1分查询还在进行,这个时候有个用户做了一个转账,把从李四的卡里面转了300给张三,当用户读取到李四这个记录的时候,如果返回的结果是700,那么就是一个不可重复读
幻影读
10点发起了一个全表扫描,10点过1分的时候查询还在进行,然后在10点过2分insert了一条记录为vic,那么查询到这个记录的时候是否会读取,如果读取了那就是是一个幻影读
维护这几种数据库一致性oracle都是通过undo的方式去实现的
一致性的另外一个情况,如果说有两个用户同时想修改表中的一行怎么办??
测试:
锁的特点:
自动管理
伴随整个事物
锁的种类:
1、DML锁
在对数据进行修改的时候就会产生DML锁,一个事务会产生两把锁,一个是行级别的TX锁,一个是表级别的表级共享锁
为什么要有TX和TM的存在呢?
select sid,TYPE,ID1,ID2,LMODE,REQUEST,CTIME from v$lock; --发起dml,使用语句查询
TX(行级别)
保护事务中某一行的一致性
TM(表级别)
尝试drop table;
2、DDL锁
3、LATCH
队列机制,先进先出,一个个的排队
DML锁
TX锁:
通过一个具体的sql,去理解DML锁
用户发出 update emp set sal=100 where empno=7369;
1、找到empno=7369这行的位置,比如说在100号块上面
2、分配undo数据块,并且把7369这个人原来的sal的值放入到undo上面
3、在数据块上分配一个ITI槽,记录事务id,undo的地址,scn,状态(是否提交)等信息
4、找到empno=7369这行的记录,在行头设定锁标记,记录当前事务的iti号
5、把控制全交给用户
在第四步 行头的时候就是一个TX锁。
问题:
如果需要跟新的不是一行记录呢??where deptno=10?? 会有几个TX锁?
因为这三条记录是属于同一个事物的的,tx是叫事物排它锁。
测试:
SQL> update emp set sal=100 where empno=7369; --有几个TX锁、几个TM锁
1 row updated.
SQL>
SQL>
SQL>
SQL> update emp set sal=10 where deptno=30; --有几个TX锁、几个TM锁
6 rows updated.
SQL>
SQL> update dept set loc='GZ' where deptno=10;--有几个TX锁、几个TM锁
1 row updated.
v$lock
ADDR 锁对象的地址
KADDR
SID
TYPE 锁类型
ID1 锁标示
ID2 锁标示
LMODE 锁模式 下面会将到
REQUEST 要求得到什么样的锁模式,0表示不要求
CTIME
BLOCK
一个个的介绍这里面的字段
TX锁、TM锁中ID1,ID2的含义
为TM锁时候,ID1表示被锁定的对象的OBJECT_ID,ID2此时为“0”。
TX锁的时候 ID1对应视图V$TRANSACTION中的XIDUSN字段(Undo segment number:事务对应的撤销段序列号)和XIDSLOT字段(Slot number:事务对应的槽位号)。其中ID1的高16位为XIDUSN,低16位为XIDSLOT。
查看高16位对应的值:
select trunc(131076/power(2,16)) XIDUSN from dual;
查看低16位对应的值:
select bitand(131076,to_number('ffff','xxxx'))+0 XIDSLOT from dual;
16为这个东西。。。 不用管
v$transaction
每一个事务在v$transaction里面有个记录
XIDUSN:就是事务的回滚段号
XIDSLOT:就是ITL列表中,slot的号
XIDSQN:就是表示这个slot被重复使用的次数
对lock来说,使用的是先到先得的机制,会有一个锁队列去控制
测试:
session 1 update dept set loc='GZ' where deptno=10;
session 2 update dept set loc='BJ' where deptno=10;
session 3 update dept set loc='SZ' where deptno=10;
select sid,TYPE,ID1,ID2,LMODE,REQUEST,CTIME from v$lock where type in ('TM','TX');
当session 1释放锁的时候,session2 和session 3谁先会获取到锁资源??
TM 锁
锁模式 锁描述 解释 SQL操作
0 none
1 NULL 空 Select
2 SS(Row-S) 行级共享锁,其他对象只能查询这些数据行 、Lock for update、Lock row share
3 SX(Row-X) 行级排它锁,在提交前不允许做DML操作 Insert、Update、Delete、Lock row share
4 S(Share) 共享锁 Create index、Lock share
5 SSX(S/Row-X) 共享行级排它锁 Lock share row exclusive
6 X(Exclusive) 排它锁 Alter table、Drop table、Drop index、Truncate table 、Lock exclusive
alter table t move;
insert into t values xxxx;
手工锁定表:没有理由不要这样做
LOCK TABLE emp in ROW SHARE mode;
LOCK TABLE emp in ROW EXCLUSIVE mode;
LOCK TABLE emp in SHARE mode;
LOCK TABLE emp in SHARE ROW EXCLUSIVE mode;
LOCK TABLE emp in EXCLUSIVE mode;
可以用这个测试一下其它的锁冲突
========================================
DDL锁
在DDL语句时产生的锁
排他DDL锁
drop table
alter table
share DDL锁
create procure 里面有很多对象,会在对应的对象上加一个共享的DDL锁,共享锁的目的是为了防止别人获得排他性的锁
死锁:
session 1
update scott.emp set sal=1 where empno=7369;
session 2
update scott.emp set sal=1 where empno=7499;
这个时候session 1 想更新7499
session 1
update scott.emp set sal=1 where empno=7499; --被hang住,啥都动不了
如果session2再去update 7369呢?
session 2
update scott.emp set sal=1 where empno=7369; --理论上也会被hang住,7369被session1获取,要等session1,但是session1要更新7499,由于被session2阻塞,啥都动不了,session2去等一个啥都动不了的session 结果就是永远等待,oracle发现这个问题会自动打破这个死锁
=============================================
解锁
解锁最简单的就是在进行了增删改查的用户进行commit或rollback就可以了提交事物就自动解锁,但是在不知道谁的情况下又是如何解锁了;
select sid,serial#,event from v$session where event like '%TX%'; --查看数据库的情况
select sid,serial#,event,blockint_session from v$session where event like '%TX%'; --看谁被锁了
select sid,serial#,username,machine,blocking_session from v$session where sid=1; 查看罪灰祸手
alter system kill session '1,18'; 根据查出来的sid 和serial# 能确定是谁了然后kill 掉