维护数据的完整性
数据的完整性:用于确保数据库遵从一定的商业逻辑规则,在oracle中,数据完整性可以使用约束、触发器,应用程序(过程,函数)三种方法来实现。在这三种方法中,因为约束易于维护,并且有良好的性能,所以作为维护数据完整性的首选。
商业逻辑规则:
性别:男 女
年龄:0-150
约束 not null 非空
用于指定某列的值,不能为空。
create table nulltest(id number not null,uname varchar2(20));
insert into nulltest(uname) values ('张三');--报错
约束 primary key 主键
用于唯一的标示表行的数据,当定义主键约束后,该列不能重复且不能为null;
create table primarytest(id number primary key,uname varchar2(20));
insert into primarytest(uname) values ('张三');--报错
insert into primarytest values (1,'张三');
insert into primarytest values (1,'李四');--报错
约束 unique 唯一
用于指定某列的值,不能重复,但是可以为null。
create table uniquetest(id number unique,uname varchar2(20));
insert into uniquetest(uname) values ('张三');
insert into uniquetest values (1,'张三');
insert into uniquetest values (1,'李四');--报错
约束 foreign key 外键
外键指向主键列或者指向unique列。
外键列和主键列数据类型要一致。(长度可以不一致,大于小于都行) 定义的时候尽量保持一致
建表时先建立主表,再建立从表。【主表 被依赖的表 class,从表 studentforeigntest 】
删除时要先删除从表,再删除主表。
从表添加数据的外键列的值必须在主键列中存在,如果不存在,加不进去。但是可以为空。
正确示例: primary key
create table class(id number primary key,uname varchar2(20));
create table studentforeigntest(id number primary key , classId number references class(id));
drop table class;--删除失败
错误示例:
create table studentforeigntest(id number primary key , classId number references class(id));--创建失败
正确示例: unique
create table class(id number unique,uname varchar2(20));
create table studentforeigntest(id number primary key , classId number references class(id));
约束 check 检查
用于强制数据必须满足的条件。【同where语句的写法】
create table checkTest(id number check(id>10 and id <100),uname varchar2(20));
insert into checkTest(uname) values ('张三');--不传值可以
insert into checkTest values (1,'张三');--报错
insert into checkTest values (15,'张三');
主键和unique的区别
一个表可以有多个unique,但是只能有一个主键。
unique的值可以为空,但是主键不可以。
primary key的所在列,会自动创建索引,但是unique不会。
建议:
我们每张表都应该有一个主键,但是不一定需要unique。
综合案例
论坛用户信息注册
客户姓名不能为空 且唯一
手机号码不能重复 作为主键
客户的性别必须是男或女 默认是男
create table userInfo(
uname varchar2(20) not null unique,-- 主键只能有一个
phone number(11) primary key,
gender char(2) default '男' check(gender in ('男','女'))
);
默认值 default
create table testdefault(
id_number number primary key,
id_name varchar2(20) default '默认名称'
);
insert into testdefault values(1,null);--没有默认名称
insert into testdefault values(2,'');--没有默认名称
insert into testdefault(id_number) values (3);--有默认名称 --开发使用较多
insert into testdefault values(4,default);--有默认名称
insert into testdefault values(5,'default');--写入default
建表之后增加约束
create table userInfo2(
uname varchar2(20),
phone number(11),
gender char(2)
);
增加非空约束 使用modify
写法:alter table 表名 modify 列名 not null;
alter table userInfo2 modify phone not null;--设置不允许为空
alter table userInfo2 modify phone null;--设置允许为空
添加unique约束 使用add
写法:alter table 表名 add constraint 约束名称 unique (列名+);
alter table userInfo2 add constraint uniId unique (phone);
alter table userInfo2 add constraint uniId2 unique (phone,uname);
添加check约束 使用add
写法:alter table 表名 add constraint 约束名称 check(检查内容)
alter table userInfo2 add constraint checkId check(gender in ('男','女'));
alter table userInfo2 add constraint checkid2 check(length(phone)=11);
添加主键约束 使用add
写法:alter table 表名 add constraint 主键名 primary key(列名+)
alter table userInfo2 add constraint primaryId primary key(uname);
alter table userInfo2 add constraint primaryId primary key(uname,phone);
添加外键约束 使用add
写法:alter table 表名1 add constraint 外键名 foreign key (列名) references 表名2(主键或者unique列)
alter table userInfo2 add constraint foreignId foreign key (classid) references class(id);
删除约束
非空约束直接设置为null。
alter table userInfo2 modify phone null;--设置允许为空
除了非空约束,其他约束都是,alter table 表名 drop constraint约束名。
alter table userInfo2 drop constraint checkId;
特殊的:主键唯一,不需要约束名也可以删除
alter table userInfo2 drop primary key;
当遇到主从关系(外键约束),会提示无法删除,在后面添加cascade。【级联删除】,会同时删除外键。
alter table class drop constraint SYS_C0016927 cascade;
列级定义和表级定义
在定义的同时,直接在列后定义约束,我们称之为列级定义。
表级定义,把各个列都定义完之后,再添加约束我们称之为表级定义。
not null只能使用列级定义。【回顾为什么只有非空是modify】
一般情况下,我们使用列级定义即可,但是如果遇到复合主键,复合unique,则只能使用表级定义。
【不推荐大家使用复合主键】
序列
需求:希望在添加记录的时候,我们希望有一列number类型,当我们添加一条记录的时候该列值可以自动增长,比如从1开始增长,每次增长1。
解决:oracle利用序列(sequence)来完成。
- 可以为表中的列自动产生值。
- 由用户创建数据库对象,并可由多个用户共享。
- 一般用于主键或唯一列。
--创建序列
create sequence myseq
start with 1 --从1开始
increment by 1 --按照1 增长
minvalue 1 --最小值
maxvalue 30000 -最大值
cycle --循环利用 到了最大值后又重新开始 nocycle 不循环 默认是不循环
nocache --缓存 cache 10 一次产生10个号 优点:提高效率 缺点:产生跳号
--取得当前值
select myseq.currval from dual;
--取得下一个值 序列名.nextval
select myseq.nextval from dual;
--直接使用序列的值插入表中 【大量使用的场景】
insert into userInfo2 values('张三','12345678900','男',myseq.nextval);
update userInfo2 set classId = myseq.nextval ;
注意事项:
currval必须在第一次nextval初始化之后才能使用,否则会出错。
使用场景:
订单号。
索引
考虑问题:
图书馆找图书按照分类来查找。
数据库找数据按照取模来查找。【打比方,不是真正的实现原理】
索引的分类:单列索引 复合索引。
如何创建一个索引
单列索引
写法: create index 索引名 on 表名(列名);
create index index1 on userInfo2(classId);
复合索引
写法: create index 索引名 on 表名(列名+);
create index index2 on userInfo2(classId,uname);
使用原则:
- 在大表上建立索引才有意义。
- 在where子句或是连接条件上经常使用到的位置上建立索引才有意义。
- 在逻辑类型字段或者枚举值字段上也不要建立索引。
索引的缺点:
占用更多空间:建立索引之后,系统要占用大约为表的1.2倍的硬盘和内存空间来保存索引。
影响插入,删除,修改的效率:更新数据之后,系统需要额外的时间来维护数据的索引。 【批量更新数据的时候删除索引】
不恰当的位置:
- 很少或者基本不用来作为查询条件的列。
- 逻辑型字段,枚举型字段 (是否,性别 ,年级)
视图
视图是一个虚拟表,其内容由查询定义。同真实的表一样,视图包含一系列带有名称的列和行数据。但是视图并不在数据库中以存储的数据集形式存在。行和列数据来自由定义视图的查询所用的表,并且在引用视图时动态生成。
视图主要用于简化操作,提高安全性,满足不同用户的查询需求。
需求:创建和emp表(empno,ename,job)完全一致的视图。
写法:create view 视图名 as 查询语句 [with read only]?
写法:create or repalce view 视图名 as 查询语句 [with read only]?
create view empview as select empno,ename,job from emp;
如果scott没有权限,切换到sys 执行下列语句
grant create view to scott; --通过sys给SCOTT赋权限 创建视图的权限
不带with read only 意味着可以对视图进行修改操作。
真正有价值的视图:
需求:查询雇员的名字和部门名称。
--创建视图
create view empview
as select ename,dname from emp,dept
where emp.deptno = dept.deptno
with read only;
--创建或者替换视图
create or replace view empview
as select ename,dname from emp,dept
where emp.deptno = dept.deptno
with read only;
删除视图:drop view 视图名
分页
select emp.*,rownum from emp where rownum<=6 and rownum>=4;--oracle认为这样效率低,无法查询出来结果
select temp.*,rownum from (select emp.* from emp where rownum<=6) temp where rownum>=4;
--没有结果
原因解析:oracle内部优化机制,不返回查询结果,我们可以通过下面语句验证内容是有的。
select temp.*,rownum from (select emp.* from emp where rownum<=6) temp;--可以查询到结果
解决方案:对rownum使用别名。
select temp.*,rownum from (select emp.*,rownum rn from emp where rownum<=6) temp where rn>=4;--正确分页
【缺点】 如果要作为一个分页模板,修改不方便。可以进行优化,优化为三层模板。
思考,按照入职时间的先后顺序,查询第七到第10个人的信息?
select temp.*,rownum from (select emp.*,rownum rn from emp where rownum<=6) temp where rn>=0;--能看到所有列
6 表示取到第6条。
4 表示从第4条开始取。
分页模板优化——三层过滤
select temp.*,rownum from (select innerTemp.*,rownum rn from (select * from emp) innerTemp where rownum<=6) temp where rn>=4;
优化的好处:
以后只需要修改内层查询语句select * from emp
已经开始,结束位置。
效率模拟检测:
create table empbak as select * from emp;
insert into empbak select * from empbak;--自我复制 百万数量级测试
select temp.*,rownum from (select innerTemp.*,rownum rn from (select * from empbak) innerTemp where rownum<=600000) temp where rn>=599900;--越是后面的数据越是慢
rowid 和 rownum的区别
rowid和rownum都是虚列,但含义完全不同。rowid是物理地址,用于定位oracle中具体数据的物理存储位置,而rownum则是sql的输出结果排序。
通俗的讲:rowid是相对不变的,rownum会变化,尤其是使用order by的时候。
oracle的事务处理
现象:多个控制台同时操作数据库,如果某个控制台更新了数据没有提交,这个控制台看到的数据就和其他控制台不一致了。
数据库把一系列对于数据库的操作看成一个整体,要么全部成功,要么全部失败,这样的现象就是事务。事务具有原子性。
生活示例:转账。
commit 提交
rollback 全部回滚
savepoint 保存点名称; --设置保存点,可以设置多个
注意:一旦回退到前面的保存点,就无法再获取之后的保存点。
rollback to 保存点名称;--回退到保存点
权限
权限分为系统权限和对象权限。
系统权限 【熟悉】
系统权限:对数据库的管理操作以及对数据对象的操作(创建,删除,修改)。
对象权限:对数据对象的操作(select,insert,update,delete)
常用的系统权限:
create session 连接数据库
create table 建表
create view 建视图
查询所有系统权限
select * from system_privilege_map;--查询系统权限
赋权限:
一般来说,授予系统权限是dba来完成的,如果用其他用户来授予权限,则要求该用户具有grant any privilege的系统权限。在授予权限的同时可以带有with admin option选项,这样被授予权限的用户或是角色还可以将权限授予其他用户或者角色。
使用sys用户作为sysdba登录
创建用户
create user authuser identified by 123456;--用于测试有with admin option
create user noauthuser identified by 123456;--用于测试没有with admin option
sys 给用户授权
grant create session to authuser with admin option;
grant create table to authuser with admin option;
grant create session to noauthuser;
grant create view to noauthuser;
authuser 给 noauthuser授权
grant create table to noauthuser;
回收权限
revoke create table from authuser;
问题:
如果authuser将create table权限赋给 noauthuser,sys又将authuser的create table权限回收,noauthuser还能创建表么?
还能建表。 类比行政职位分封。
对象权限 【熟悉,相对重要】
访问其他方案对象的权限。【访问其他用户的对象】
常用对象权限
alter 修改 insert 添加 delete 删除 select 查询 index 索引 references 引用 excute 执行
查询所有对象权限
select distinct privilege from dba_tab_privs;--需要使用dba用户查询
授予对象权限:
在oracle9i之前,授予对象权限是由对象的所有者来完成的,如果用其他的用户来操作,需要用户具有相应的权限(with grant option),从oracle 9i开始,sys,system用户可以将任何对象上的对象权限授予其他用户,授予对象的权限是用grant命令来完成的。
grant 对象权限 on 数据库对象 to 用户名[角色名] [with grant option]
--使用sys将scott的emp表的查询权限赋给authuser 并给与其赋权给其他人的权限
grant select on scott.emp to authuser with grant option;
--使用sys将scott的empbak表的所有权限赋给authuser
grant all on scott.empbak to authuser;
--使用authuser将权限赋给noauthuser
grant select on scott.emp to noauthuser;
--使用scott将emp表的select权限赋给noauthuser
grant select on empbak to noauthuser;
注意:with grant option选项只能授予用户,不能授予角色。
回收用户权限:
--sys赋予的权限all,可以通过scott回收,也可以部分回收
revoke alter on empbak from authuser;
--使用sys回收所有权限
revoke all on scott.empbak from authuser;
--使用sys回收authuser在scott.emp上的select权限
revoke select on scott.emp from authuser;
问题:回收了authuser对于emp的select权限之后,authuser赋给noauthuser的权限还在么?
不在了。 对象权限是使用权限,类比借出物品。
注意:使用revoke的时候,如果是没有分配过的权限,revoke会报错,只有revoke all没有问题。
角色
角色的本质是多个权限的集合,用于简化对权限的管理。
数据库角色分为预定义角色和自定义角色。
预定义角色
问题:假定现在3个用户,为了让他们都有权限。
- 连接数据库权限;
- select,insert,update权限;
总共需要进行12次授权。
解决:使用自定义角色。
预定义角色:
预定义角色是指oracle所提供的角色,每种角色都用于执行一些特定的管理任务。
常见角色:connect角色 dba 角色 resource角色
同时赋connect和resource角色可以满足大部分开发人员的要求。
select * from dba_roles;--查询所有角色
查询角色具有的权限
select * from dba_sys_privs where grantee = 'DBA';--查询DBA具有的权限
赋角色
grant 角色名 to 用户
grant connect to authuser;
回收角色
revoke 角色名 from 用户
revoke connect from authuser;
查询用户具有的角色
select * from dba_role_privs where grantee = 'AUTHUSER';--查询authuser具有的角色
dba角色
dba角色具有所有的系统权限,及with admin option选项,默认的dba用户为sys和system,他们可以将任何系统权限授予其他用户,但是要注意的是dba角色不具备(启动和关闭数据库)。
自定义角色
预定义角色不能满足要求,可以使用自定义的角色来解决。一般是具有dba权限的用户来建立。如果用别的用户来建立,则需要具有create role的系统权限。在建立角色时可以指定验证方式(不验证,数据库验证等)
建立角色(不验证):【一般使用这种方式】
create role 角色名 not identified;
create role dboprole not identified;--创建自定义角色
给角色赋权限
grant create session to myrole;
grant select on scott.empbak to myrole;
grant insert on scott.empbak to myrole;
grant delete on scott.empbak to myrole;
将这个角色赋给指定用户
grant 角色名 to 用户名 [with admin option]
grant myrole to authuser;
删除角色
drop role 角色名;
建立角色(数据库验证):采用这样的方式时。角色名,口令存放在数据库中。当激活该角色时,必须提供口令,在建立这种角色时,需要为其提供口令。
create role 角色名 identified by 密码
create role myrole2 identified by 234567;
启用角色
set role 角色名 identified by 密码
set role myrole2 identified by 234567;
grant create session to myrole2;
grant select on scott.empbak to myrole2;
grant insert on scott.empbak to myrole2;
grant delete on scott.empbak to myrole2;
方案【了解】
方案是oracle创建数据对象的方式。
当一个用户创建任意一个数据对象后,DBMS就会创建一个与之同名的方案,该用户创建的数据库对象会放入该方案中。