Oracle从入土到诈尸
本笔记不适合初学者。本笔记不适合初学者。本笔记不适合初学者。
Oracle基础语法
增删改查
SELECT
查询1
SELECT column1, column2 FROM table_name WHERE condition;
INSERT
插入1
INSERT INTO table_name (column1, column2) VALUES ('value1', 'value2');
UPDATE
修改1
UPDATE table_name SET column1 = 'value' WHERE condition;
DELETE
删除1
DELETE FROM table_name WHERE condition;
like
like
用于模糊匹配。
1 | SELECT column1 FROM table_name WHERE condition LIKE 'expression'; |
例如:要查询名字中含有字符’a’的人的信息:
1 | SELECT * FROM table_name WHERE ename LIKE '%a%'; |
order by
按照一个列或多个列进行排序,可选参数有ASC
升序排序和DESC
降序排序。
group by
按照一个列和多个列进行分组,和聚合函数一起使用。
基础函数
本章节仅介绍一些常用函数。
函数测试一般使用dual
表,该表没有数据,查询什么就返回什么。
数值函数
abs(x)
:返回x的绝对值。1
2-- 123
SELECT abs(-123) from dual;mod(x, y)
:返回x除以y的余数。
在mod(x, y)
中,没有正负数的概念,结果只和x的正负性相关。取余操作是一个持续相减的过程,通过x持续减去y,我们可以还可以得到x的小数部分:当y=1时,可以直接得到x的小数部分。1
2
3
4
5
6-- 3
SELECT mod(13, 5) FROM dual;
-- 0.556
SELECT mod(12.556, 1) FROM dual;
-- 4
SELECT mod(4, 12) FROM dual;ceil(x)
和floor(x)
:向上取整和向下取整。1
2-- 13 and 12
SELECT ceil(12.556),floor(12.556) FROM dual;round(x,[d])
:对x进行四舍五入,默认不保留小数。可选参数d表示要保留的小数位数。1
2
3
4-- 13
SELECT round(12.556) FROM dual;
-- 12.56
SELECT round(12.556, 2) FROM dual;trunc(x,[y])
:截取数字x。y默认为0。如果y为正数,则截取小数点后y位;如果为负数,则先保留整数部分,然后从个位开始向前y位,并将遇到的数字都变为0。该函数不进行四舍五入,直接截取。1
2
3
4
5
6-- 12
SELECT trunc(12.556) FROM dual;
-- 12.55
SELECT trunc(12.556, 2) FROM dual;
-- 10
SELECT trunc(12.556, -1) FROM dual;sign(x)
判断x的正负。正数返回1,负数返回-1,0返回0。1
2-- 1
SELECT sign(12) FROM dual;power(x,y)
:返回x的y次方。1
2-- 2的3次方,8
SELECT power(2, 3) FROM dual;
字符函数
- 大小写切换
大小写切换分为三个函数:upper(s)
、lower(s)
和initcap(s)
。upper(s)
用于将字符串s转为大写,lower(s)
用于将字符串s转为小写,initcap(s)
仅仅将字符串s首字母转为大写。1
2
3
4
5
6-- SOMETHING
SELECT upper('SOMEthing') FROM dual;
-- something
SELECT lower('SOMEthing') FROM dual;
-- Something
SELECT initcap('something') FROM dual; length(s)
和lengthb(s)
:用于计算字符串的字符和字节长度。1
2
3
4-- 2
SELECT length('你好') FROM dual;
-- 6
SELECT lengthb('你好') FROM dual;trim(s)
:去除字符串两端的空格。
去除函数还有ltrim(s1, [s2])
和rtrim(s1, [s2])
,默认去除字符串s1左侧/右侧的空格,添加参数s2后用于去除字符串s1左侧/右侧的s2。1
2
3
4-- something
SELECT trim(' something ') FROM dual;
SELECT ltrim(' something') FROM dual;
SELECT rtrim('somethingaaaaa', 'a') FROM dual;lpad(s1, x, s2)
和rpad(s1, x, s2)
:在字符串s1左侧/右侧填充s2直到整个字符串的长度为x。1
2
3
4-- hhhhhhello
SELECT lpad('hello', 10, 'h') FROM dual;
-- worldddddd
SELECT rpad('world', 10, 'd') FROM dual;instr(s1, s2, [x, [y]])
:在s1中从第x位开始,查找s2第y次出现的位置。- x和y默认为1。
- 如果x为负数,则从后往前查找。
1
2
3
4
5
6-- 5
SELECT instr('hello world', 'o') FROM dual;
-- 8
SELECT instr('hello world', 'o', 1, 2) FROM dual;
-- 8
SELECT instr('hello world', 'o', -1) FROM dual;
substr(s, x, [y]])
:在s中从第x位开始截取字符串,截取长度为y。- 如果省略y,则从第x位开始截取到末尾。
- 如果x为负数,则从倒数第x位开始截取。
1
2
3
4
5
6-- world
SELECT substr('hello world', 6) FROM dual;
-- llo wor
SELECT substr('hello world', 3, 7) FROM dual;
-- rld
SELECT substr('hello world', -3) FROM dual;
replace(s1, s2, [s3]
将s1中的s2替换为s3,s3不写则替换为空。1
2
3
4-- hello oracle
SELECT replace('hello world', 'world', 'oracle') FROM dual;
-- hello
SELECT replace('hello world', ' world') FROM dual;translate(s1, s2, s3)
:将s1中的s2逐一替换为s3。translate()
中可以使用额外的字符用于将某些文本替换为空(不是s1中出现的字符就行)。1
2
3
4
5
6-- 这是一二三四五
SELECT translate('这是12345', '12345', '一二三四五') FROM dual;
-- heo word
SELECT translate('hello world', '*l', '*') FROM dual;
SELECT translate('hello world', '?l', '?') FROM dual;
SELECT translate('hello world', 'al', 'a') FROM dual;
转换函数
to_number(s)
:将字符串s转换为数字。to_date(s,r)
:将字符串s按照格式r转换为日期。
r的可选参数有:yyyy->年、mm-<月、dd->日、hh/hh24->小时/24小时制、mi->分钟、ss->秒、day->星期、d->数字星期、q->季度。1
2-- 2025-01-01 12:32:55
SELECT to_date('20250101123255','yyyy-mm-dd hh24:mi:ss') FROM dual;to_char(x/d, r)
:将数字x或日期d按照格式r转换为字符串。
对于x,其格式r为:9->占位符、0->用于个位的占位符、L->本地货币、$->美元。
对于d,其格式相较于to_date()
,额外:ddd->当前天是当年的第几天、sssss->当前秒是当天的第几秒。1
2-- 2025
SELECT to_char(sysdate,'yyyy') FROM dual;
日期函数
日期函数的运算规则为:日期加减数字=日期加减天数,日期相减=日期相差的天数。
在Oracle中,可以使用sysdate
获取当前系统日期时间。
add_months(d, x)
:将日期d增加/减少x个月。month_between(d1, d2)
:日期d1和d2之间相差的月数。trunc(d, r)
:截断日期到格式r最初。r同to_date()
。1
2
3
4-- 2025-01-01
SELECT trunc(sysdate, 'yyyy') FROM dual;
-- 2025-04-03 09:00:00
SELECT trunc(sysdate, 'hh24') FROM dual;trunc()
还可以用于数字。1
2
3
4-- 12
SELECT trunc(12.556) FROM dual;
-- 12.5
SELECT trunc(12.556, 1) FROM dual;next_day(d, x)
:计算下一个星期x。
如果要计算下一个星期的星期几,可以先得到本周星期日,再计算本周日的下一个星期几。1
2
3-- 下一个星期的星期四
SELECT next_day(next_day(sysdate - 1, 1), 4) FROM dual;
SELECT next_day(next_day(sysdate - 1, '星期日'), '星期四') FROM dual;
通用函数
nvl(x1, x2)
:处理空值。如果x1为空则返回x2,否则正常返回x1。空值如果参与数学计算那么结果一定为空。distinct
:去重。和select
一起使用:select distinct ...
。case when
和decode
:条件判断。
这两者都用于条件判断,且都有两种语法。1
2
3
4
5
6
7
8
9
10CASE 字段 WHEN 结果1 THEN 返回值1
WHEN 结果2 THEN 返回值2
...
[ELSE 返回值n]
END
CASE WHEN 条件1 THEN 返回值1
WHEN 条件2 THEN 返回值2
[ELSE 返回值n]
ENDcase when
的返回值必须保持一致。1
2decode(字段, 结果1, 返回值1, 结果2, 返回值2,...[返回值n])
decode(字段, 结果, 返回值1, 返回值2)
高级函数
聚合函数
聚合函数是用于对一组值执行计算并返回单个值的函数。这些函数通常在数据分析和报告中使用,以提供对数据集的总结视图。(将多条数据高度聚合成一条数据)
聚合函数只能显示聚合函数的结果以及字段。
1 | SELECT sum(sal) FROM emp; |
常用的聚合函数具体包括count
、sum
、avg
、max
、min
、wm_concat
、listagg
。
count
、sum
、avg
、max
、min
:计算数量、总和、最大值、最小值。wm_concat
和listagg
:分组后连接字符串。
wm_concat(字段)
默认分隔符为,
,list(字段,分隔符)
可以手动指定一个分隔符,需要在后面跟上within group(order by ...)
进行分组后的排序。
分析函数
分析函数可以显示聚合的结果,也可以显示明细的字段,也被称为窗口函数。分析函数与聚合函数不同在于,分析函数可以显示聚合的结果,并且为每一组返回多个数据行,而聚合函数只能显示聚合的结果和分组的字段。
使用over
关键字可以声明分析函数。分析函数是在FROM
、WHERE
、GROUP BY
和HAVING
子句后进行计算的。
分析函数的语法为:
1 | -- 分析函数(参数) OVER (分析子句) |
分析函数可以在同一条SQL语句中指定不同的分组条件。
1 | -- 别名忘记改了,将就看吧 |
分析函数一般用于:
- 显示聚合的结果以及其他字段;
- 在一条语句中使用多个分组条件;
- 进行数据分析时;
- 进行排列、移动行时。
分析子句
分析子句分为三种:order by
、partition by
以及rows/range between
。
order by
排序,表示累积的结果。
下面示例中,表示按照部门编号对总工资进行累加。
1 | select DEPTNO,SAL,sum(SAL) over (order by DEPTNO rows between unbounded preceding and current row) as 总工资 |
partition by
分组,表示分组的条件。
下面示例中,表示分别对每个部门的总工资进行累加,按照部门编号进行分组。
1 | select DEPTNO,SAL,sum(SAL) over (partition by DEPTNO order by DEPTNO rows between unbounded preceding and current row) as 部门总工资 |
rows between
如果我们使用常规的分析函数查看累加过程,会发现在遇到相同数值的值时,分析函数会将其同时相加。
1 | SELECT ename,sal, sum(sal) OVER ( ORDER BY sal) AS 累加总和 FROM emp; |
此时,按行累计求和只需要在order by子句后加上一句:rows between unbounded preceding and current row
。
1 | SELECT ename, sal, |
对rows
的参数研究(个人分析,无参考)
rows between
是一个窗口分析子句,其取值是一个范围的形式。rows between
的常见语法见下图:
首先,先来认识一下每个词代表什么意思:
- unbounded:不限制的,无限的
- preceding:前面的
- following:后面的
- current:当前的
然后以一个SQL语句作为示范:现在,我们把下面每一条子句都代入到上面:1
select DEPTNO,SAL,sum(SAL) over ( order by DEPTNO [rows between子句] ) from EMP;
下面是一些比较长的参数:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30-- 从最开始的行到最后的行,等效于sum(),代入后每一行的数据都是累加后的总和
rows between unbounded preceding and unbounded following
-- 从最开始的行到当前行,代入后下一行的数据等于前面行的累加
rows between unbounded preceding and current now
-- 从最开始的行到当前行的前/后第value行。
-- 例如,取 1 preceding
-- SAL 值
-- 2450 NULL
-- 5000 2450
-- 1300 2450+5000=7450
-- 2975 2450+5000+1300=8750
rows between unbounded preceding and values preceding/following
-- 从当前行到最后的行,相当于将累加过程逆序开始,从结果到最开始
-- 等同于rows between unbounded preceding and current now的降序排列结果
rows between current now and unbounded following
-- 从当前行到当前行,等效于select直接查询
rows between current now and current now
-- 从当前行到当前行的前/后第value行。
-- 例如:取 1 following
-- SAL 值
-- 2450 2450+5000=7450
-- 5000 5000+1300=6300
-- 1300 1300+2975=4275
-- 2975 1300+下一行=...
rows between current now and values preceding/following
=> 从当前行前/后第values行到最后的行。观察后我们可以发现,第一行合并的值从第二行SAL开始累加,第二行合并的值从第三行SAL开始累加,一直到最后一行合并的值从第n+1行开始累加,由于最后一行的下一行为null,因此累加后得到的合并的值也为null。1
2
3rows between values preceding/following and unbound following
-- 举例:从当前行的后1行到最后的行
select DEPTNO,SAL,sum(SAL) over ( order by DEPTNO rows between 1 following and unbound following ) from EMP;
=>从当前行前/后第value行到当前行。
1 | rows between values preceding/following and current now |
我们可以很轻松的发现,第n行的合并值为第n-1行的SAL和第n行的SAL累加。由于第一行的前一行没有值,因此第一行的合并值只能得到当前的值。
=>从当前行前/后第values行到当前行前/后第values行。
1 | rows between values preceding/following values preceding/following |
这是一个非常自由的参数!
那如果,我们不需要between
呢?
当然可以,为什么不行!
1 | select DEPTNO, |
从合并的结果我们可以看到,他们都等效于rows between 上述参数 and current now
。由此我们可以得出结论,rows
单独使用时默认和rows ... between current now
具有相同的效果。
唯一需要注意的是,rows
单独使用时只能跟preceding
,不允许使用following
。
排列
排列分为三种:row_number()
、rank()
和dense_rank()
。
例如,当我们要查询emp表的工资排名:
1 | SELECT ename, sal, row_number() OVRE (ORDER BY SAL DESC) FROM emp; |
由此我们可以得到:row_number()
不并列,rank()
并列并跳一级,dense_rank()
并列不跳级。row_number()
适用于计数,rank()
适用于排名,dense_rank()
适用于颁奖。
移动行
移动行分为两种,一般用于计算环比,必须排序。number代表要移动的行数,value代表移动后出现NULL时,替换掉NULL的值。
1 | -- 上移 |
例如,将工资向上或向下移动:
1 | SELECT sal, |
集合
对于集合,我们想要添加别名,需要添加在第一条SQL语句上,而且两条SQL语句的数据类型和数量必须相对应。
- 并集
union
和union all
union
会对结果去重,而union all
不会。对于集合A和B:- A union B = A + B - A intersect B
- A union all B = A + B
- 交集
intersect
集合A和B共有的部分。 - 差集
minus
集合A拥有而集合B没有的部分,相当于A minus B = A union B - B。
行列转换
行转列(透视):一维表转为二维表
- 数据透视:将原始数据按照某一列进行分组,并将其他列的值进行合并,生成透视表。
- 数据汇总:将多个行数据按照指定的列进行汇总,生成一条汇总数据。
- 数据展示:将多条行数据进行合并,生成一行展示数据。
行转列使用pivot
函数将行数据转化为列数据。其中,被聚合的列将转化为列中的值,而列中的值将变为新增的列名。例如,我们需要将下面这张表转化为二维表:1
2SELECT * FROM table_name
PIVOT (聚合函数(被聚合的列) FOR 行转列的列 IN ('value1', 'value2', ...));
我们可以使用以下SQL语句:即可得到如下结果:1
2
3
4
5SELECT * FROM KECHENG
PIVOT (
max(SCORE) FOR COURSE IN('语文' AS 语文,'数学' AS 数学,'英语' AS 英语,'历史' AS 历史,'化学' AS 化学)
)
ORDER BY ID;
列转行(逆透视):二维表转为一维表
- 数据拆分:将一列数据按照某一列进行拆分,生成多行数据。
- 数据转换:将多列数据合并为一列,方便后续处理或分析。
- 数据规整:将多列数据进行规整,使得数据结构更加清晰和易于分析。
列转行使用unpivot
函数将列数据转化为行数据。例如:按如下格式显示7369员工的信息:1
2
3select *
from 表名
unpivot [include nulls] (被聚合的列的新列名 for 列转行的新列名 in (列1,列2...))
EMPNO KEY VALUE 7369 ename smith 7369 job clerk 7369 mgr 7902 7369 hiredate 17-12-80 7369 sal 800 7369 comm null 7369 deptno 20 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22select EMPNO, KEY, VALUE
from (select EMPNO,
ENAME,
JOB,
to_char(MGR) as mgr,
to_char(HIREDATE, 'dd-mm-yy') as hiredate,
to_char(SAL) as sal,
to_char(COMM) as comm,
to_char(DEPTNO) as deptno
from EMP
where EMPNO = 7369)
unpivot include nulls (
VALUE for KEY in (
ENAME as 'ename',
JOB as 'job',
MGR as'mgr',
HIREDATE as 'hiredate',
SAL as'sal',
COMM as 'comm',
DEPTNO as 'deptno'
)
);即可将原来列的信息转化为行:
子查询
单行子查询
单行子查询返回的结果是单行单列,即一个值。
单行子查询在where
子句中可以使用单行比较运算符(=, >, >=, <, <=, <>),将。返回结果当做单一数值来使用。
单行子查询返回的结果有三种:
- 返回单行:即单行子查询。
- 返回多行:即多行子查询,此时不允许使用单行比较运算符。
- 未返回行:子查询相当于返回null,此时主查询将不再执行,不会返回任何结果。
多行子查询
多行子查询的结果返回的是多行单列。
多行子查询在where
子句中可以使用多行比较运算符(IN, ALL, ANY),将子查询的返回结果当做数值集合来使用。ALL和ANY必须和单行比较运算符结合使用。例如:where SAL > ANY(子查询)
。
- IN:等于任何一个。
- ALL:和子查询返回的所有值比较,例如
SAL > ALL(1, 2, 3)
等价于SAL > 3
。 - ANY:和子查询返回的任意值比较,例如
SAL > ANY(1, 2, 3)
等价于SAL > 1
。 - EXISTS:判断子查询是否有返回结果(不关注内容),有返回结果则返回true,否则为false。EXISTS常用于相关子查询。
多列子查询
多列子查询的结果返回的是单行多列或者多行多列,也可以是不返回结果。
- 单行多列:可以使用单行比较运算符。
- 多行多列:只能使用多行比较运算符。
表连接
内连接
内连接是最常见的连接类型,它只返回两个表中匹配的行。如果表中有列名相同的字段,可以使用自然连接(Natural Join),Oracle会自动找出这些字段并进行连接。内连接的标准语法如下:
1 | SELECT table1.column, table2.column |
在实际应用中,如果没有特别指定,join
默认为inner join
,因此inner
关键字可以省略。
例如,查询EMP表和DEPT表中的员工姓名,工资,部门编号和部门名称:
1 | select ename, SAL, EMP.DEPTNO, DNAME |
如果两个表中有同名的列,可以在连接子句中使用using(同名列)
,此时语法中没有on
。
下面的SQL语句和上方等效。
1 | select ENAME,SAL,DEPTNO,DNAME |
外连接
外连接包括左外连接、右外连接和全外连接:
left join
:显示左表的独有数据和两张表的共有数据。right join
:显示右表的独有数据和两张表的共有数据。full join
:显示两张表的独有数据和共有数据。left join
和right join
都以一张表为基础表,另一张表为附加表,基础表的内容全部显示,然后再加上两张表匹配的内容。 如果基础表的数据在附加表中没有记录, 那么在相关联的结果中附加表的列会用null补齐。对于全连接,则是互相用null补齐。
外连接的标准语法如下:在Oracle中,还可以使用1
2
3
4SELECT table1.column, table2.column
FROM table1
LEFT|RIGHT|FULL OUTER JOIN table2
ON table1.column1 = table2.column2;(+)
操作符来表示外连接,但它只能用于左连接和右连接,不能用于全连接。(+)
代表附加表,在左边代表左表为附加表,即右连接。反之则为左连接。
以下两条SQL语句等效。1
2
3
4
5
6
7select ENAME,SAL,EMP.DEPTNO,DNAME
from EMP right join DEPT
on EMP.DEPTNO = DEPT.DEPTNO;
select ENAME,SAL,EMP.DEPTNO,DNAME
from EMP,DEPT
where EMP.DEPTNO(+) = DEPT.DEPTNO;
不等值连接
主要用除了=
之外的操作符,比如:<>、>、<、>=、<=、LIKE、IN、BETWEEN…AND
。
自然连接
自然连接是根据两个表中同名的列而进行连接的,当列不同名时,自然连接无意义。自然连接中语法中没有on。
以下两条SQL语句等效。
1 | select ENAME,DEPTNO,SAL,DNAME |
交叉连接(笛卡尔积)
交叉连接(笛卡尔积)返回被连接的两个表所有数据行的笛卡尔积,返回结果集合中的数据行数等于第一个表中符合查询条件的数据行数乘以第二个表中符合查询条件的数据行数。
[!NOTE]
设A,B为集合,用A中元素为第一元素,B中元素为第二元素构成有序对,所有这样的有序对组成的集合叫做A与B的笛卡尔积,记作AxB.
笛卡尔积的符号化为:
AxB={<x,y>|x∈A∧y∈B}
例如,A={a,b},B={0,1,2},则
AxB={<a,o>,<a,1>,<a,2>,<b,0>,<b,1>,<b,2>,}
BxA={<0,a>,<0,b>,<1,a>,<1,b>,<2,a>,<2,b>}
交叉连接有三种语法:
1 | SELECT * FROM table1 CROSS JOIN table2; |
数据库五大语言
不当运维用不上系列。
真想看记得多练啊多练啊多练啊😦😦😦
DQL数据库查询语言
前面看的都是的。
DCL数据库控制语言
DCL用于管理数据库访问权限,包括以下三种命令:
grant
:用于给用户或用户组授予访问数据库的权限。revoke
:用于从用户或用户组中撤销访问数据库的权限。deny
:用于阻止用户或用户组访问数据库。
[!NOTE]
修改用户密码:
1 alter user 用户名 identified by "密码";
用户权限分类
用户权限分为系统权限和实体权限,系统权限只能由DBA用户授予。
系统权限分为dba
、resource
、connect
。
dba
:拥有全部特权,是系统最高权限,只有该权限才可以创建数据库结构。resource
:拥有该权限的用户只可以创建实体,不可以创建数据库结构。connect
:拥有该权限的用户只可以登录Oracle,不可以创建实体,不可以创建数据库结构。
实体权限分为select、update、insert、alter、index、delete、all
。作用同名。
1 | -- 给用户赋权 |
DDL数据库定义语言
DDL全称是Data Definition Language,即数据定义语言,定义语言就是定义关系模式、删除关系、修改关系模式以及创建数据库中的各种对象,比如表、聚簇、索引、视图、函数、存储过程和触发器等等。
数据定义语言是由SQL语言集中负责数据结构定义与数据库对象定义的语言,并且由create
、alter
、drop
和truncate
四个语法组成。
create
create
用于创建,例如创建表、视图、索引、存储过程等。
1 | create table book(bno varchar2(20) primary key,-- 图书编号 |
alter
alter
用于修改数据库中的对象,包括add
、rename
、modify
、drop
等。
例如,将emp表的员工编号设置为主键:
1 | alter table EMP add constraint pk_e_empno primary key (EMPNO); |
当然,我们也可以在创建表的时候就设置主键:
1 | create table table_name ( |
还有以下语法:
1 | -- 为e表的deptno添加外键约束(fk_e_d),关联到d表的deptno,指定级联删除为空 |
drop
&truncate
—危险操作—
区别于delete
,首先delete
属于DML,当不commit时时不生效的,意思commit前可以回滚。而truncate
和drop
则是直接生效的,不能回滚。truncate
和delete
不删除表的结构,只是针对表中的内容删除。drop
语句将删除表的结构,被依赖的约束(constrain)、触发器(trigger)、索引(index)以及依赖于该表的存储过程/函数将保留,但是变为invalid状态。truncate
会释放占用空间,而drop
和delete
不会。
唯一有用的应该是: 执行速度上,drop > truncate > dalete
。全删了能不快吗
DML数据库操作语言
DML主要由insert
、delete
、update
组成。
和select
差不多,用着用着就会了。
TCL 事务控制语言
详情请见下一章事务。
事务
事务的四个特性:
- 原子性:事务包含的操作要么成功要么失败,成功则改变数据库,失败则不影响。
- 一致性:事务执行前和执行后保持一致。
- 隔离性:多个用户并发访问数据库时,相互隔离。
- 持久性:事务提交对数据库的改变是永久的,即使数据库故障,也不会丢失事务操作。