目录
一、事务
1.1.为什么要使用事务?
在SQL中,数据管理语言帮助我们对数据库中保存的数据进行我们想要的操作:增删改查等。从现实逻辑中看,我们的增删改查的操作最终都需要在数据库中实际保存的值中有一个具体的体现。
也就是说,我们执行了insert语句,我们的保存的记录就会添加一条新的记录。但是,这会产生一个问题,那就是数据的安全性。
情况一:假设我们对数据进行了修改,但是在修改的数据还没有传输完毕写入数据库的时候我们的服务器关闭了,导致只传了一半,那么我们的数据是不是变成了我们原本想象中的一半。比如,我们传输的是abcd,但是最终保存的是ab
上面的情况只是单向传输。
对于双向传输而言,我们的情况可能更加难过,假设你要给你的朋友转账,在系统中把你的钱扣掉之后,发生了上述情况,导致你朋友没有收到你的转账,这就会导致,你白白丢失了你的money,这无疑是不可行的。
情况二:我们对数据进行了操作,SQL语句的编写是由人类编写的,既然是人类编写的,那么难免会有一些失误,当我们SQL语句编写出错了,但是语法上没有问题,那么就会导致我们的数据库的其他信息被污染,此时,我们又不知道被污染的记录的原本数据是什么,就会产生错误。
正是因为这样多种多样的问题的出现,所以,我们需要事务的出现。
1.2.什么是事务?
事务指作为单个逻辑工作单元执行的一组相关操作。这些操作要求全部完成或者全部不完成。使用事务是为了保证数据的安全有效。
什么意思呢?
简单来说,事务就是把整个事情变成一个整体,当事务完成的时候,才会真正对数据进行修改,如果事务没有正常执行完毕,被中途阻止了,就不会对数据产生干扰。
1.3.事务的特点ACID
原子性(Atomic) | 事务中所有数据的修改,要么全部执行,要么全部不执行。 |
一致性(Consistence) | 事务完成时,要使所有的数据都保持一致的状态 换言之:通过事务进行的所有数据修改,必须在所有相关的表中得到反映。 |
隔离性(Isolation) | 事务应该在另一个事务对数据的修改前或者修改后进行访问。 |
持久性(Durability) | 保证事务对数据库的修改是持久有效的,即使发生系统故障,也不应该丢失。 |
理解:
原子性:事务不可分割,要么事务完成,数据发生更新;要么事务未完成,数据保持原样
一致性:事务完成后,数据被修改,与被修改数据相关的表中的数据也会相应的进行修改
隔离性:事务在并发执行的时候不会互相影响,在两个事务不同的执行过程中,我们两个事务的结果应该是串行运行的结果,也就是说,我们的一个事务的执行不应该会收到另外一个事务的影响,但是因为执行效率的问题,所以,我们规定了不同的隔离级别,只有在隔离级别最高的情况下才是串行的。
持久性:事务执行完毕后,数据就会发生修改,而且,数据的修改是直接保存到数据库中,持久化的存储。就相当于我们的事务完成后,最新的数据被保存到了一个硬盘中。
1.4.事务的隔离级别
1.4.1.为什么需要隔离级别?
事务的四大特性中原子性,一致性,持久性,都是对于单个事务而言的,但是对于多个事务而言,如果我们要保证数据的安全性,我们就要保证事务的隔离性。
简单来说,要实现一个优秀的事务,我们就需要在编写代码的时候来保证隔离性
1.4.2.什么是隔离级别
隔离级别就是对隔离性的分类。
对于事务,我们要保证其隔离性,但是对于不同的应用场景,我们需要使用不同的标准来保证不同事务操作同一数据的隔离性。如果我们的隔离级别只有一个,在需要保证事务的隔离性的前提下,我们就需要将事务变为串行执行,那么事务本身就变成了不可并发,此时就会是的事务的执行效率大大下降;而有的时候,我们的事务不需要使其串行就足以保证隔离性,此时,我们就需要另一个标准。
简单来说,在不同的应用场景中,我们达成不同的隔离级别就可以实现事务本身的隔离性
1.4.3.隔离级别的分类
隔离级别 | 脏读 | 不可重复读 | 幻读 |
Read uncommitted(读未提交) | 是 | 是 | 是 |
Read committed(读已提交) | 否 | 是 | 是 |
Repeatable read(可重复读) | 否 | 否 | 是 |
Serializable(串行读) | 否 | 否 | 否 |
Oracle的默认隔离级别是Read committed;
它支持Read committed和Serializable两种隔离级别;它还定义了Read only和Read write隔离级别
Read only:事务中不能有任何修改数据库中数据的操作语句,是 Serializable 的一个子集。
Read write:默认设置,该选项表示在事务中可以有访问语句、修改语句,但不经常使用。
Read uncommitted(读未提交)
理解:
一个事务能够看到能够看待其他事务未提交的修改,这是最低的隔离级别,脏读、不可重复读、幻读都有可能出现。
选择:
也就是说,如果我们的事务可能出现这三种情况,就不能使用这种隔离级别。
Read committed(读已提交)
理解:
事务能够看到的数据是其他事务已经修改并提交后的数据。但是,这种隔离级别并不是能够完全保证两次读取数据的一致性,它是允许两个事务同时并发的对同意数据进行修改
选择:
所以,当我们的事务可能出现不可重复度和幻读的时候就不能使用这种隔离级别,换句话说,当我们事务只可能出现脏读的时候,就使用这种隔离级别
Repeatable read(可重复读)
理解:
事务重复读取得到的数据一致,见名知意,在同一事务中,无论在什么时候读取同一份数据,得到的结果都是相同的。它是通过将读取出来的记录加锁来实现的,即当事务A读取到该组数据,此时这些数据就被锁住了,不会再有其他事务对这些记录进行修改,这就完美的防止了脏读和不可重复读的出现。
选择:
此种隔离级别就不会在发生脏读和不可重复读的情况,所以,当我们的事务中不会出现幻读的情况的时候,就可以使用这个隔离级别
Serializable(串行读)
理解:
所谓的串行读就是,并发的事务之间是串行执行的,也就是说,对于串行读而言,所有的数据是排队执行的,事务A执行的时候不允许事务B来执行。
选择:
当我们的事务可能会出现幻读的时候,就使用串行读的隔离级别;
如果我们不确定使用哪种隔离级别,那么就先使用串行读
1.4.4.事务并发可能出现的问题
丢失更新
情况一:事务A和事务B,事务A先查询数据为5,后事务B对此数据进行了加5,则数据变为10,提交事务B,后事务A对此数据进行减5,修改此数据为10,但是事务A并没有提交,而是进行了回滚,数据则回到了5,最终结果为5。丢失了B的更新。
情况二:事务A和事务B,事务A先查询数据为5,后事务B对数据进行减5,数据修改为0,提交事务B,后事务A对其进行对数据进行加5,修改数据为10,提交事务A,最终数据为10。丢失了B的更新。
脏读
事务A和事务B,事务A先查询数据5,并对数据进行了加5的操作,此时,事务A并没有提交,但是事务B却读取到了事务A还没有提交的数据,并在此基础上进行操作;最终事务A没有提交此次修改,进行了回滚,那么事务B进行的数据修改就是在一个无效的数据上进行的修改。
不可重复读
重复读是指的在一个事务中发生了多次读取同一数据的情况。
事务A和事务B,事务A第一次读取了数据5,此时事务A还未执行完毕;事务B在并发情况下,也读取了数据5,并对数据进行了加5的操作,导致数据变为10;此时,在事务A中在执行到第二次读取该数据的时候,发现与第一次读取的数据不同,这就是不可重复读
幻读
指当事务不是独立执“行数据”操作时发生的一种现象。
事务A和事务B,事务A读取了数据5并对数据进行了加5的操作;但是在执行加5的操作过程总,事务B向数据中添加了一条新记录,之后事务A发现数据多了一条没有被更新的数据,好像产生了幻觉一样。
总结:
解决不同的数据出错情况所应该使用的隔离级别,依照1.4.3中的表来进行选择。
1.5.事务的使用
1.5.1.事务的开启
自动开启于 DML 之 insert delete update
在关系数据库中,一个事务可以是一条SQL语句,一组SQL语句或整个程序。
1.5.2.事务的结束
成功
1.正常执行完成的 DDL 语句:create、alter、drop
2.正常执行完 DCL 语句 GRANT、REVOKE
3.正常退出的 SQLPlus 或者 SQL Developer 等客户端
4.如果人工要使用隐式事务,SET AUTOCOMMIT ON (只针对一个连接)
5.手动提交 :使用 commit
失败
1.rollback ,手动回滚
2.非法退出 意外的断电
注意:
rollback只能对未提交的数据进行回滚的操作,对于已经提交了的数据不能进行rollback,这是因为事务一旦被提交,就会被持久化到数据库中。
二、约束
2.1.对于约束的基本概念
参照以下章节2.4.3
Oracle03-DML数据操控语言-DDL数据定义语言_czttaotao的博客-CSDN博客
参照以下章节3.3
Oracle01-课程背景-基本概念-DQL查询语句_czttaotao的博客-CSDN博客
2.2.约束相关的方法
2.2.1.查看某个用户的约束
select constraint_name, constraint_type
from user_constraints
where owner = upper('SCOTT');
2.2.2.查看表的约束
select constraint_name, constraint_type
from user_constraints
where table_name = upper('emp')
2.2.3.查看 字段名+约束
select constraint_name, column_name
from user_cons_columns
where table_name = upper('emp');
2.2.4.约束的禁用与启用
ALTER TABLE tb_user disable constraint nn_user_name;
ALTER TABLE tb_user enable constraint nn_user_name;
2.2.5.删除约束
alter table tb_user drop constraint uq_user_email cascade;
2.2.6.修改约束
--非空
alter table tb_user modify (username varchar2(20));
--默认
alter table tb_user modify (age default null);
三、视图
3.1.为什么要使用视图?
视图是一张虚拟的表,当我们的一条SQL语句中,大量重复应用了某一条SQL语句的时候,我们就可以将这条SQL语句封装到一个视图中,此时,我们就可以直接使用视图来代替这条SQL语句,达到代码重复使用,极大减少我们的重复性编码的行为
3.2.视图的作用
1. 简化:select 查询语句
2. 重用:封装select语句 命名
3. 隐藏:内部细节
4. 区分:相同数据不同查询
3.3.视图的分类
逻辑视图 | 不存储数据,只封装了SQL,数据是来源于数据源 |
物理视图|物化视图 | 可以存储数据 |
3.4.视图的使用
3.4.1.视图的创建
--创建视图 create or replace view 视图名 as select语句 [with read only];
create or replace view vw_xixi as select empno,ename,sal,deptno from emp where sal>1500 with read only ;
问题:视图并没有创建成功
分析:这是因为,我们登录的账户是普通用户,而一个视图要保证的是所有用户都可以使用,普通用户的权限是无法支持我们做到这一步的。
解决:
为我们的普通用户添加权限。我们不是所有的用户都可以创建视图,我们需要管理员来授予权限,普通用户才可以创建视图。
步骤:
1.sys登录
2.授权:grant dba to scott;
3.回收: revoke dba from scott;
3.4.2.视图的删除
--删除视图
drop view vw_xixi;
3.4.3.视图的例子
以往的写法
--查询每个部门经理人的平均薪资最低的部门名称
--1)所有的经理人
select distinct mgr from emp where mgr is not null;
select * from emp where empno in (select distinct mgr from emp where mgr is not null);
--2)找到所有部门中最低的平均薪资
select min(avg(sal))
from emp
where empno in (select distinct mgr from emp where mgr is not null)
group by deptno;
--3)经理人按照部门分组,部门编号,平均薪资
select deptno,avg(sal)
from emp
where empno in (select distinct mgr from emp where mgr is not null)
group by deptno having avg(sal) = (最低平均薪资);
select deptno
from emp
where empno in (select distinct mgr from emp where mgr is not null)
group by deptno
having avg(sal) = (select min(avg(sal))
from emp
where empno in
(select distinct mgr from emp where mgr is not null)
group by deptno);
--4)根据部门编号找到部门名称
select dname
from dept
where deptno =
(select deptno
from emp
where empno in (select distinct mgr from emp where mgr is not null)
group by deptno
having avg(sal) = (select min(avg(sal))
from emp
where empno in (select distinct mgr
from emp
where mgr is not null)
group by deptno));
使用视图后
--新建视图,封装sql
create or replace view vw_mgr as select distinct mgr from emp where mgr is not null with read only ;
select dname
from dept
where deptno = (select deptno
from emp
where empno in (select * from vw_mgr)
group by deptno
having avg(sal) = (select min(avg(sal))
from emp
where empno in (select * from vw_mgr)
group by deptno));
四、索引
4.1.索引的作用
索引的作用就相当于一个目录,通过目录可以提高我们查询的速度。
4.2.创建索引
--create index 索引名 on表名 (字段列表...)
create index index_sal on emp(sal);
4.3.删除索引
--drop index 索引名
drop index index_sal;
4.4.总结
1.相当于目录
2.唯一性较好字段适合建立索引
3.无形的,字段是否存在索引,不影响使用
4.索引本身是数据库的对象之一,需要数据库维护
5.根据字段大量做查询,而大数据量的查询适合添加索引
6.如果一个字段添加了索引,少做查询,大量增删,反而会降低效率,因为索引要更新,需要维护
7.oracle数据库会自动为主键添加索引
五、序列
5.1.什么是序列?
管理表中一些数字型的字段的字段值,是一个工具。
简单来说,序列就是用来帮助我们为表中的数字型数据赋值,他能保证我们数字型数据的规律和不可重复。
5.1.1.序列的语法
create sequence 序列名 start with 起始值 increment by 步进;
5.2.序列的实现逻辑
当我们的序列被创建的时候,我们可以设置一个起始值和步进。起始值就是指的是我们序列刚被创建还未被使用的时候所代表的最新值。
我们使用一次序列,序列的当前值就会被当次所使用的最新值覆盖,新的最新值是原值在自身的基础上加上我们设定好的步进。
5.3.序列的方法
5.3.1.nextval获取最新值
--获取最新值
select seq_deptno.nextval from dual;
5.3.2.currval获取当前值
--获取当前值
select seq_deptno.currval from dual;
5.4.使用序列
5.4.1.创建序列
--创建 create sequence 序列名 start with 起始值 increment by 步进;
create sequence seq_deptno start with 50 increment by 2;
5.4.2.调用序列进行赋值
insert into dept values(seq_deptno.nextval,'xx','xx');
5.4.3.删除序列
--删除序列
drop sequence seq_deptno;