oracle学习笔记 事务概述
Posted 新站
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了oracle学习笔记 事务概述相关的知识,希望对你有一定的参考价值。
oracle学习笔记 事务概述
这节课讲oracle的事务
一)什么是事务
oracle的事务单纯从开发角度来讲它比较简单
很多人认为oracle的事务就是两个,一个是commit一个是rollback
oracle中最重要的就是数据的一致性、数据的安全以及oracle数据的优化
这几块是非常重要的
事务它关系到数据的一致性
对oracle数据库来讲或者对任何数据库来讲数据的一致性是重中之重
作为DBA去维护oracle数据库
把数据给搞坏了搞的不一致了这个是不允许的
这是DBA来讲所有错误的一个底线
不能出现数据不一致的情况
事务从简单的概念上来讲就是一组DML语句
所谓DML语句无非就是有insert数据的插入,还有delete,还有update
主要就这几个语句
oracle开发里面还有一些别的DML语句如CALL、EXPLAIN PLAN等
主要的DML语句就是对数据进行操作的增删改
事务就是一组DML语句,看上去是一组DML语句
输入一组DML语句以后然后输入commit,就把这个事务给提交了
rollback就是把这个事务给它回滚了回退了
我们可以这么认为
commit以后这一组DML语句所产生的效果被保存起来了
rollback以后这一组DML语句所修改的数据被回退了,也就是相当于没有修改
事务从简单的理解上就这么简单
事务的操作命令commit、rollback还有SAVEPOINT、ROLLBACK TO、SET TRANSACTION等
它们都是属于oracle的数据控制语言DCL。
二)演示一个事务
简单演示一下
1)搭建环境
先登陆数据库
老师讲课使用的是hr用户
本人数据库安装时创建了这个用户
但还没有使用过hr用户
这里给它解锁并且赋予密码
[oracle@redhat4 ~]$ sqlplus / as sysdba
SQL*Plus: Release 10.2.0.1.0 - Production on Mon May 15 10:06:56 2017
Copyright (c) 1982, 2005, Oracle. All rights reserved.
Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
SQL> alter user hr account unlock;
User altered.
SQL> alter user hr identified by hr;
User altered.
然后使用hr用户登陆
[oracle@redhat4 ~]$ sqlplus hr/hr
SQL*Plus: Release 10.2.0.1.0 - Production on Mon May 15 10:10:57 2017
Copyright (c) 1982, 2005, Oracle. All rights reserved.
Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
SQL>
登陆成功!
这个账户没有激活时sqlplus用hr登陆的时候可能会报一些错
报错的时候提示用户被锁住了
可以给它解开
上面例子我用了两个sql语句也可以用它们合成的一个sql语句
用sys用户登陆进去以后,然后
alter user hr account unlock identified by hr;
把hr用户这个账号解锁,同时把密码给它改成hr
然后hr可以登陆了
hr登陆后执行
select * from user_tables;
显示的结果字段太多影响查看
所以改为
SQL> select table_name from user_tables;
TABLE_NAME
------------------------------
REGIONS
LOCATIONS
DEPARTMENTS
JOBS
COUNTRIES
JOB_HISTORY
EMPLOYEES
7 rows selected.
比老师结果少了一个T1表,因为我还没有建这个表
这里自己建一下
SQL> create table t1(id int,name varchar2(20));
Table created.
然后插入一行数据
SQL> insert into t1 values (1,'xkj');
1 row created.
提交
SQL> commit;
Commit complete.
这样就和老师讲课此表的状态一样了。
新建一个hr用户的会话
再次执行
SQL> select table_name from user_tables;
TABLE_NAME
------------------------------
REGIONS
LOCATIONS
DEPARTMENTS
JOBS
T1
COUNTRIES
JOB_HISTORY
EMPLOYEES
8 rows selected.
和老师的结果一样了,这里有个表t1
SQL> select * from t1;
ID NAME
---------- --------------------
1 xkj
t1表中有一行数据
2)事务的开始
这里这个会话打开以后,还没有执行DML语句,只是执行select
这个时候其实还没有开始一个事务
然后我们去开始一个事务
第一个问题什么叫开始一个事务
开始和结束一个事务的标识是什么
一个会话登陆以后
执行的第一条DML语句,就是一个事务的开始
我们先看一下目前数据库系统有什么事务
select xidusn,ubablk,ubafil from v$transaction;
需要系统管理员账号执行此语句才有结果
因为v$transaction动态视图属于系统管理员
非管理员用户想使用这种系统表要得到管理员的授权才可使用
因为实际生产中一般不会给链接的用户这种权利,这里就不演示授权的情况了
SQL> select xidusn,ubablk,ubafil from v$transaction;
no rows selected
结果为空,表示目前没有事务
用hr用户执行一条语句
做一个插入
SQL> insert into t1 values(2,'jiagulun');
1 row created.
我们执行了一条DML语句了
一个事务开始了
系统账号查询事务
SQL> select xidusn,ubablk,ubafil from v$transaction;
XIDUSN UBABLK UBAFIL
---------- ---------- ----------
5 627 2
结果出现一个事务
表示一个事务开始了
hr用户insert以后查一下insert里面的数据
SQL> select * from t1;
ID NAME
---------- --------------------
1 xkj
2 jiagulun
一个1,一个2
接着hr用户update更新
SQL> update t1 set name='xkjjiagulun' where id=1;
1 row updated.
又执行了一条sql语句DML语句
这两条DML语句,一个insert一个 update
都属于一个事务,一直没有提交
insert是一个事务的开始
update和insert同时属于一个事务
这时系统账号查一下当前的事务
SQL> select xidusn,ubablk,ubafil from v$transaction;
XIDUSN UBABLK UBAFIL
---------- ---------- ----------
5 627 2
事务没有改变还是原来的一个
hr查询一下
SQL> select * from t1;
ID NAME
---------- --------------------
1 xkjjiagulun
2 jiagulun
然后hr再删一行数据
SQL> delete from t1 where id=1;
1 row deleted.
这时还是一个事务
目前事务还没有结束
3)事务的结束
事务的开始我们看到了
一个事务结束可以用commit
commit以后你所做的前面所做的修改全部保存
全部为永久保存
如果rollback
你前面所做的,这个事务所做的修改,自动取消
比如这里执行rollback
hr用户执行
SQL> rollback;
Rollback complete.
系统用户查一下事务
SQL> select xidusn,ubablk,ubafil from v$transaction;
no rows selected
没有事务了
rollback取消了,刚才所做的DML语句全当没有发生过
你就认为它没有发生过
hr用户执行
SQL> select * from t1;
ID NAME
---------- --------------------
1 xkj
一个事务在rollback的时候结束了
rollback结束一个事务后,也意味着我们可以开始一个新的事务
一个事务结束了,我们可以开始一个新的事务
比如这里hr用户再接着执行
SQL> insert into t1 values(2,'beijing');
1 row created.
执行了一条DML语句
因为前面执行rollback的时候一个事务已经结束了
结束以后在insert的时候一个新的事务开始了
系统账号查一下当前的事务
SQL> select xidusn,ubablk,ubafil from v$transaction;
XIDUSN UBABLK UBAFIL
---------- ---------- ----------
7 1811 2
又有了一个新的事务,并且和前面查询到的事务不一样,不是一个事务
当出现第一个DML的时候事务开始了
一个事务的结束,是rollback或commit都可以
一个事务的结束意味着另外一个事务可以开始了
hr用户接着执行
SQL> insert into t1 values(3,'china');
1 row created.
这里hr用户执行了两条DML语句
然后提交
SQL> commit;
Commit complete.
提交以后这个事务
上面两个insert所在的事务,就被保存了
也就是说这个事务结束了
hr用户查当前数据
SQL> select * from t1;
ID NAME
---------- --------------------
1 xkj
2 beijing
3 china
系统账号查当前的事务
SQL> select xidusn,ubablk,ubafil from v$transaction;
no rows selected
这个事务结束意味着一个新的事务可以开始了
事务说白了说的很简单就是这样。
三)保存点savepoint的使用
1)savepoint的实际使用
还有个savepoint命令
我们再开始一个事务
hr用户先查一下
SQL> select * from t1;
ID NAME
---------- --------------------
1 xkj
2 beijing
3 china
有三行数据了
SQL> select xidusn,ubablk,ubafil from v$transaction;
no rows selected
并且没有任何事务
SQL> insert into t1 values(4,'qingdao');
1 row created.
输入一个insert
一个事务开始了
SQL> select xidusn,ubablk,ubafil from v$transaction;
XIDUSN UBABLK UBAFIL
---------- ---------- ----------
3 735 2
执行savepoint起名随便起一个x1
SQL> savepoint x1;
Savepoint created.
再插入数据
SQL> insert into t1 values (5,'jinan');
1 row created.
执行到这个时候后悔了
insert语句执行多了
我想回滚
我不想回滚id为4的那一条
只想回滚到id为5的位置
这里在插入id为5的行前建了一个点x1
先查一下
SQL> select * from t1;
ID NAME
---------- --------------------
1 xkj
2 beijing
3 china
4 qingdao
5 jinan
然后回滚
SQL> rollback to x1;
Rollback complete.
只回滚到x1的位置
查一下表
SQL> select * from t1;
ID NAME
---------- --------------------
1 xkj
2 beijing
3 china
4 qingdao
数据4存在,数据5不见了已被上面的rollback to 回滚掉
再看一下当前的事务
SQL> select xidusn,ubablk,ubafil from v$transaction;
XIDUSN UBABLK UBAFIL
---------- ---------- ----------
3 735 2
还是那个事务,没有结束也没有改变
说明rollback to语句可以回滚数据但不会结束事务
这个时候我可以继续回滚,也可以继续往前作
如果rollback to后回滚
SQL> rollback;
Rollback complete.
SQL> select * from t1;
ID NAME
---------- --------------------
1 xkj
2 china
3 beijing
数据回滚
SQL> select xidusn,ubablk,ubafil from v$transaction;
no rows selected
并且事务结束
如果rollback to后提交
SQL> commit;
Commit complete.
SQL> select * from t1;
ID NAME
---------- --------------------
1 xkj
2 china
3 beijing
4 qingdao
数据被提交
SQL> select xidusn,ubablk,ubafil from v$transaction;
no rows selected
并且事务结束
rollback to 是回滚到一个已设置的savepoint的点上
不会结束整个事务
rollback是回滚到整个事务的开始,即使有savepoint点的设置也不会去理会
并且会结束整个事务
2)savepoint的意义
这个地方简单描述一下,还是很有意义的一个
这面看不出有多大意义,但是实际在工作中有帮助
记住了一个事务可以回滚一半
savepoint就是
一个事务开始了
执行了很多
在过程中的一个位置设置savepoint
然后又执行了很多
中间有可能突然发现savepoint点的后面的一条语句有问题
就可以从最后一个修改rollback到savepoint点的位置
这样有问题的语句被回滚
这样可以从savepoint接着往下面做
如我们想对数据库做一个比较大的批量操作一个非常大的一系列DML操作
这个批量操作有可能中间会失败
比如说有一万条sql语句
它作为一个transaction一个事务要执行
为了执行成功为了能够执行的更好一些
我每一千条的时候建一个savepoint
如果我失败的话我最多回滚一千条然后可以继续
否则比如一万条语句执行
我执行到9999条的时候或最后一条执行的时候失败了
或者我在最后一条执行的时候在第一万条执行的时候
我发现9998条语句我执行是失败的
如果没有加savepoint
就要也只能全部回滚
这个地方知道这么个东西
以后你应用的时候自然就会灵活去使用
这是关于事务
从简单来讲就是这些东西
四)事务中的概念
事务的基本概念包括:
一组DML语句 insert、delete、update
和
COMMIT;
ROLLBACK;
SAVEPOINT
ROLLBACK TO [SAVEPOINT]
事务就是一组DML语句
这组DML语句使用COMMIT和ROLLBACK来结束
commit意味着这一组DML语句全部被保存
rollback意味着这一组DML语句全部被回退,全部被后悔了
即使SAVEPOINT加了回退点rollback也是全部回退并且结束事务
五)实例崩溃后事务的回滚
1)事务中出现实例崩溃
有种情况数据库正常运行期间
我执行了一组DML语句
这组DML语句我还没有提交数据库突然崩溃了
举个很有帮助的一个小例子
数据库正常运行期间
数据库实例有
buffercache和数据文件
一个session登上来
每个session登上来以后都会有一个SID(session id)
登完了以后它执行了一组DML语句
本身要执行十条
它执行了五条
因为要执行十条,还没执行完所以还没有提交
数据库突然崩溃了
崩了后数据库重启了
前面讲过实例的崩溃恢复
我们知道这个事务所对应的脏块有可能被回滚回来
这个会话登上来以后
执行了五条DML语句修改了八个块
其中有六个块所对应的日志已经写到redolog里面去了
还有两个块对应的日志在logbuffer里面
因为这个事务没有提交
它的日志它所有的日志不一定全部保存到redolog里面去
然后数据库崩了,崩了以后重启以后
我们知道oracle要跑日志
从LRBA到On Disk RBA跑这个日志
跑完日志以后
前面的六个脏块被构造出来了
也就是修改的前六个块被构造出来了
后面的两个块没有被构造出来,没有被跑出来
因为它在logbuffer里面,没有磁盘日志跑不出来
但这六个块对我们来讲没有意义
因为这个特定的会话,登上来以后执行了五条DML语句
但这个会话的这个事务还没有提交
数据库关了这个会话就死了
这个会话死了
也就是这个会话永远不可能再重现了
即使是这个人重新再登陆上来
它也是启的另外一个会话
2)一个会话不能重现
一个会话一旦死掉
退出以后
这个会话不可能再重新建立
即使是同样的机器同样的人用同样的用户名密码登陆以后
它产生的也是另外一个会话
这个我们可以查一个v$session看一下
SQL> desc v$session
Name Null? Type
----------------------------------------- -------- ----------------------------
SADDR RAW(4)
SID NUMBER
SERIAL# NUMBER
AUDSID NUMBER
PADDR RAW(4)
USER# NUMBER
USERNAME VARCHAR2(30)
COMMAND NUMBER
OWNERID NUMBER
TADDR VARCHAR2(8)
LOCKWAIT VARCHAR2(8)
STATUS VARCHAR2(8)
SERVER VARCHAR2(9)
SCHEMA# NUMBER
SCHEMANAME VARCHAR2(30)
OSUSER VARCHAR2(30)
PROCESS VARCHAR2(12)
MACHINE VARCHAR2(64)
TERMINAL VARCHAR2(30)
PROGRAM VARCHAR2(48)
TYPE VARCHAR2(10)
SQL_ADDRESS RAW(4)
SQL_HASH_VALUE NUMBER
SQL_ID VARCHAR2(13)
SQL_CHILD_NUMBER NUMBER
PREV_SQL_ADDR RAW(4)
PREV_HASH_VALUE NUMBER
PREV_SQL_ID VARCHAR2(13)
PREV_CHILD_NUMBER NUMBER
MODULE VARCHAR2(48)
MODULE_HASH NUMBER
ACTION VARCHAR2(32)
ACTION_HASH NUMBER
CLIENT_INFO VARCHAR2(64)
FIXED_TABLE_SEQUENCE NUMBER
ROW_WAIT_OBJ# NUMBER
ROW_WAIT_FILE# NUMBER
ROW_WAIT_BLOCK# NUMBER
ROW_WAIT_ROW# NUMBER
LOGON_TIME DATE
LAST_CALL_ET NUMBER
PDML_ENABLED VARCHAR2(3)
FAILOVER_TYPE VARCHAR2(13)
FAILOVER_METHOD VARCHAR2(10)
FAILED_OVER VARCHAR2(3)
RESOURCE_CONSUMER_GROUP VARCHAR2(32)
PDML_STATUS VARCHAR2(8)
PDDL_STATUS VARCHAR2(8)
PQ_STATUS VARCHAR2(8)
CURRENT_QUEUE_DURATION NUMBER
CLIENT_IDENTIFIER VARCHAR2(64)
BLOCKING_SESSION_STATUS VARCHAR2(11)
BLOCKING_INSTANCE NUMBER
BLOCKING_SESSION NUMBER
SEQ# NUMBER
EVENT# NUMBER
EVENT VARCHAR2(64)
P1TEXT VARCHAR2(64)
P1 NUMBER
P1RAW RAW(4)
P2TEXT VARCHAR2(64)
P2 NUMBER
P2RAW RAW(4)
P3TEXT VARCHAR2(64)
P3 NUMBER
P3RAW RAW(4)
WAIT_CLASS_ID NUMBER
WAIT_CLASS# NUMBER
WAIT_CLASS VARCHAR2(64)
WAIT_TIME NUMBER
SECONDS_IN_WAIT NUMBER
STATE VARCHAR2(19)
SERVICE_NAME VARCHAR2(64)
SQL_TRACE VARCHAR2(8)
SQL_TRACE_WAITS VARCHAR2(5)
SQL_TRACE_BINDS VARCHAR2(5)
数据库当前所有的会话都在这里面
它有session ID即SID
可以使用
select a.sid,a.serial# from v
sessiona,v
mystat b where a.sid=b.sid;
简单的看一下当前所有的会话的sid和它的序列号
执行结果
SQL> select a.sid,a.serial# from v$session a,v$mystat b where a.sid=b.sid;
SID SERIAL#
---------- ----------
147 538
147 538
147 538
.
.
.
147 538
147 538
363 rows selected.
结果太多只列出一部分
SID是147
SERIAL是538
这就是当前我的session
因为v
session,v
mystat是系统视图
所以hr用户执行这条语句会提示视图不存在
当前会话关闭
再新建一个系统管理员会话
在此会话中执行这条语句
SQL> select a.sid,a.serial# from v$session a,v$mystat b where a.sid=b.sid;
SID SERIAL#
---------- ----------
144 734
144 734
144 734
.
.
.
144 734
144 734
363 rows selected.
这个新会话
SID是144
serial是 734
退出这个会话
SQL> exit
Disconnected from Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
原来的会话已经死掉了
再建立一个新会话
[oracle@redhat4 ~]$ sqlplus hr/hr
SQL> connect / as sysdba
在这个会话中使用上面的sql查询
SQL> select a.sid,a.serial# from v$session a,v$mystat b where a.sid=b.sid;
SID SERIAL#
---------- ----------
129 1098
129 1098
129 1098
.
.
.
129 1098
129 1098
363 rows selected.
可以看到
会话和以前不一样了
我们把结果复制下来
现在的会话是
129 1098
这是会话的编号
然后退出
SQL> exit
还是同样的机器
还是同样的用户名密码
[oracle@redhat4 ~]$ sqlplus / as sysdba
然后重新执行一下上面的sql语句
SQL> select a.sid,a.serial# from v$session a,v$mystat b where a.sid=b.sid;
SID SERIAL#
---------- ----------
129 1156
129 1156
129 1156
.
.
.
129 1156
129 1156
363 rows selected.
结果是
129 1156
把这两个结果放到一起进行比较
第一个结果
129 1098
第二个结果
129 1156
我们发现结果不一样
serial不一样
一个是1098一个是1156
也就是说
一句话
一个会话死掉以后,无论是退出还是数据库崩溃,这个会话不可能重现了
那么这个会话不可能重现了
意味着当年没有完成的事务不能再回来了
也就是说这个事务不可能再完成了
事务所依赖的会话死掉了
这个事务不可能再完成了
所以这个事务只能被回滚
3)未完成事务的回滚
我们再来简单描述一下
数据库正常运行期间
一个会话登陆上来,会话有SID有serial
这个会话执行了一个事务开始了一个事务
这个事务有十条DML语句,但它只执行了五条产生了八个脏块
其中有六个脏块产生的日志已经写到磁盘上,有两个还在buffer里面
数据库突然崩了
崩了以后,然后数据库重启
重启了以后
我们知道oracle会跑日志
跑日志的时候
前六个脏块又被构造出来了
但是有一个问题我们有一个原则
一个会话一旦死掉以后这个会话不可能再生
会话不可能再生
这个会话当年所执行的没有完成的事务不可能再完成了
这个时候这个事务只能被回滚
oracle会自动的对这个事务回滚
这个事务这个SID
所执行的DML语句
其中有六个块被构造出来了
将来这六个块所做的修改会自动被rollback
对oracle数据库来讲
如果数据库崩了它首先要前滚
前滚完了对未完成的事务还要回滚
一个事务要么全成功要么全失败
不可能出现一个事务运行一半的情况
也就是说在oracle数据库里面
不可能出现一个事务跑了一半然后被保存了然后可以被访问
一个事务要么全成功要么全失败
这是事务的基本概念
事务有commit或者rollback可以提交和回滚
另外一种情况
数据库如果突然崩了
这时候数据库所有未提交的事务会被自动回滚
这也是一种被回滚的情况
五)DDL语句的提交
还有DDL语句
就是create建表的和删表的等等这些语句
我执行了一条DDL
比如create
这时oracle自动的在执行create以前,会自动的执行commit
执行完create以后,也自动的执行一个commit
执行DDL时候自动对前面的操作自动提交
举个例子
hr用户
SQL> desc t1;
Name Null? Type
----------------------------------------- -------- ----------------------------
ID NUMBER(38)
NAME VARCHAR2(20)
SQL> select * from t1;
ID NAME
---------- --------------------
1 xkj
2 beijing
3 china
4 qingdao
然后
SQL> delete from t1 where id=1;
1 row deleted.
删除了一行数据,没有提交
这时候建另外一个表
SQL> create table t2(id int,name varchar2(20));
Table created.
在执行delete以后
接着执行一个create
oracle在执行DDL语句前面会自动加一个隐含的一个commit
后面也有一个commit
也就是create前面的delete不小心被提交了
这也是一种提交方式
这时候有可能出现问题
比如我突然后悔了
SQL> select * from t1;
ID NAME
---------- --------------------
2 beijing
3 china
4 qingdao
发现坏了,不小心把这个数据删了
我想回滚
SQL> rollback;
Rollback complete.
再去看
SQL> select * from t1;
ID NAME
---------- --------------------
2 beijing
3 china
4 qingdao
发现数据没有回来
也就是说在执行DDL的时候,已经隐含的被提交了
六)正常退出和事务提交
另外一个退出exit
大家要注意
有时候这个地方很容易犯错
SQL> commit;
Commit complete.
提交了
SQL> select * from t1;
ID NAME
---------- --------------------
2 beijing
3 china
4 qingdao
再删一条数据
SQL> delete from t1 where id=2;
1 row deleted.
SQL> select * from t1;
ID NAME
---------- --------------------
3 china
4 qingdao
2给删了
这时候我修改了但是这个事务没有提交
我退出
SQL> exit
Disconnected from Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
然后再去登陆
[oracle@redhat4 ~]$ sqlplus hr/hr
看一下
SQL> select * from t1;
ID NAME
---------- --------------------
3 china
4 qingdao
发现事务退出以后事务被提交了
执行delete时并没有提交
然后exit时正常退出,发现事务被提交了,保存生效了
也就是说
不小心正常退出以后
我们所做的我们的事务被隐含的提交了
这个地方比较可怕
我们有的DBA作完操作以后吃饭去了exit退出了
退出以后可能它的操作不想保存但结果保存了
七)想模仿异常退出却都造成正常的退出
1)x窗口
还有异常退出
SQL> delete from t1 where id=3;
1 row deleted.
删了以后异常退出
比如把建立会话的putty客户端这个窗口直接给X掉
但是这时PuTTY提示
确定要关闭本会话么?
既然有了这个提示表示也就并非异常退出了
可能这时对会话执行了退出命令
这时再去看
[oracle@redhat4 ~]$ sqlplus hr/hr
查一下
SQL> select * from t1;
ID NAME
---------- --------------------
4 qingdao
发现第3号也被提交了
2)ctrl+d
会话中按ctrl+d组合键仍是一样属于正常退出
SQL> delete from t1 where id=4;
1 row deleted.
SQL> select * 以上是关于oracle学习笔记 事务概述的主要内容,如果未能解决你的问题,请参考以下文章