1、事务
(transaction)事务就是将一系列操作作为一个不可分割的整体,要么一起执行失败,要么一起执行成功 。
事务是一个不可分割的工作逻辑单元。
所有数据库中的增删改实现都是通过事务来实现的。
事务具备四个属性ACID:
原子性:(Atomicity)事务是一个完整的操作。事务的各步操作时不可分的(原子性);要么都执行,要么都不执行。
一致性:(Consistency)当事务完成时,数据必须处于抑制状态。
隔离性:(Isolation):对数据进行修改的所有并发事务是彼此隔离的,这表明事务必须是独立的,它不应以任何方式依赖于或影响其他事务。
永久性:事务完成后,它对数据库的修改被永久保持,事务日志能够保持事务的永久性。
管理事务的语句
commit 提交事务
savepoint 记录回滚点
rollback 回滚事务
commit提交
为了保证JAVA程序可以正确访问到数据库的数据内容,必须手动提交:commit。
insert,update、delete语句都需要通过事务来提交至物理文件,默认情况下所有持久化操作都是在缓存中对数据进行访问。
在DBMS关闭时数据库将自动对缓存中的数据进行commit提交。(比如在plsqldev这个dbms工具执行插入数据的操作,在物理文件的底层是看不到数据的,需要commit后才可以看到数据,关闭这个dbms工具在开启也可以看到)
select优先到数据库的缓存中查询数据,如果缓存中不存在数据则至数据文件中继续查询。
savepoint 和 rollback
例子:
declare
v_money float;
begin
--记录事务的回滚点(还原点)
--savepoint p1;
update bank set balance=balance+1200where cardId=1002;
--一个事务可以定义多个回滚点
--savepoint p2;
update bank set balance=balance-1200where cardId=1001;
--查询转账后的数据是否合法
select balance into v_money from bank where cardId=1001;
if v_moneyv_salary;
--每个员工的编号
v_id int;
--加工资的人数
v_count int:=0;
begin
--查询员工的薪资和部门编号
select salary,emp.department_id into v_salary,v_depId from emp where emp.employee_id=v_empId;
--查询员工对应的平均薪资
select avg(salary)into v_avg from emp where emp.department_id=v_depId;
--开启游标
open c_emp;
--读取游标的每一行数据
loop
fetch c_emp into v_id;
exitwhen c_emp%notfound;
--增加员工的薪资200
update emp set salary=salary+200where emp.employee_id=v_id;
v_count:=v_count+1;
end loop;
dbms_output.put_line('加薪人数是:'||v_count);
--判断员工自身薪资是否低于平均薪资
if v_salaryv_avg then
dbms_output.put_line('新增的年龄大于平均年龄');
--可以改变伪记录的数据
--:new.age:=v_avg;
--抛出异常
raise myError;
endif;
--处理异常
exception when myError then
--第一个参数是错误编号,所有自定义异常编号从-20000开始
--第二个参数是错误的信息内容
raise_application_error(-20001,'age must less than avg age!');
end;
--编写触发器,要求当用户修改emp表的数据时,salary的值必须在其岗位的薪资范围内,同时用户的薪水不超过该部门经理的薪水
create or replace trigger emp_update
before update on emp for each row
declare
PRAGMA AUTONOMOUS_TRANSACTION;
v_jobid job.job_id%type;
v_min float;
v_max float;
--部门经理的薪水
v_salary float;
--自定义异常
myError exception;
begin
--查询修改数据行对应的岗位编号
select job_id into v_jobid from emp where emp.employee_id=:new.employee_id;
--根据岗位编号查询薪资范围
select min_salary,max_salary into v_min,v_max from job where job_id=v_jobid;
--查询部门经理的薪水
select salary into v_salary from emp where emp.employee_id=(select emp.manager_id from emp where emp.employee_id=:new.employee_id);
--判断修改后的薪资是否合法
if:new.salaryv_max or:new.salary>v_salary then
raise myError;
endif;
--处理异常
exception when myError then
raise_application_error(-20001,'薪水范围错误!');
end;
update emp set salary=5600where emp.employee_id=198;
使用触发器实现成绩表的数据添加不能新增学生中学号以外的非法学号
实现思路: 用:new获取添加的学号判断在学生表是否存在
--使用触发器实现成绩表的数据添加不能新增学生中学号以外的非法学号
create or replace trigger score_insert
before insert on score for each row
--创建游标获取所有学号
declare
cursor c_stuid isselect stuId from student;
v_stuId int;
--标识新增的学号是否存在
v_hasId boolean:=false;
--异常
myError exception;
begin
--判断要新增的成绩信息中的学号是否出现在学生的学号范围内
open c_stuid;
loop
fetch c_stuid into v_stuid;
exitwhen c_stuid%notfound;
if v_stuid=:new.stuid then
v_hasId:=true;
--退出循环
exit;
endif;
end loop;
if v_hasId=falsethen
--抛出异常阻止数据的写入
raise myError;
endif;
close c_stuid;
exception when myError then
raise_application_error(-20001,'违背了外键约束!');
end;
insert into score values(1000,1,9999);
创建一个自动插入序列的触发器
--自动插入序列
create or replace trigger auto_logId
before insert on user_log for each row
begin
--将序列的值写入新纪录
select logId.nextval into:new.logid from dual;
end;
触发器还可以级联操作(比如删除主贴级联删除回帖)
7、索引
在数据库中,所有数据的存储也是按页进行存储的,通过索引能够快速定位到指定页中,再根据索引所指定的列进行快速查询。
创建索引
create index 索引名称 on 表名(列名) [tablespace 表空间名]
索引是针对某个列创建的。
使用索引合
1)数据量应至少达到10w行级别
2)频繁搜索的数据列适合建立索引
3)频繁进行排序的列适合建立索引
使用索引的注意点:
数据量过少的表格不适合建立
数据表的列被频繁修改不合适建立
8、视图 (主要用于查询)
视图就是一张通过查询获取的虚拟表,视图中本身不存在数据,数据来自于视图对源表的映射作用,一张数据表可以根据不同的需要创建多个不同的视图。
使用视图的优点:
过滤表中的行数据
组织未经授权的用户访问敏感数据
降低数据操作的复杂度
可以将多个表空间的数据抽象为一个逻辑数据
创建视图
create view 视图名称 as 查询语句
--使用视图存储允许可见的数据
create or replace view cashView asselect cardid,userName from card;
使用视图
select * from 视图名称
--使用视图查看数据
select*from cashview;
视图是对源表的映射,因此修改视图即修改源表。
比如修改视图里的用户名即对源表的数据进行修改。
--视图是对源表数据的映射,因此修改视图即修改源表
update cashView set userName='tony'where cardId='100000001';
如果视图存在多表数据,同一时间只能更新一张表。
视图可以将表中的敏感数据进行屏蔽,同时也可以将多表的数据以更直观的方式将其作为整体呈现
如下为:选择非敏感数据呈现的视图
create or replace view cashView asselect recordId,card.cardId,userName,cash,case cashtype
when1then'收入'
when0then'支出'endcase,cashtime from card inner join cashRecord on card.cardId=cashRecord.Cardid;
两张表银行卡号表,消费记录表
--银行卡号表
create table card
(
cardid varchar2(20) primary key,
userName varchar2(50)notnull,
pwd varchar(6)notnull
);
create table cashRecord
(
recordId int primary key,
cardid int,
cash float,
cashType int,--0表示支出1表示收入
cashTime date
);
这两张表以cardid关联,两张表的主键cardId、recordId
键值保留表,表示保留主键的数据表,子表必须引用主表的主键或者是唯一键,如果修改的视图中的数据列是来自于A表,此时即表示为A表依赖于B表,B表中必须要有对应的主键或者是唯一键。
视图
create or replace view cashView asselect recordId,card.cardId,userName,cash,case cashtype
when1then'收入'
when0then'支出'endcase,cashtime from card inner join cashRecord on card.cardId=cashRecord.Cardid;
对多表的视图进行修改
以下就不能修改
修改的是银行卡号表的数据,此时银行卡号表 依赖 消费记录表,但在消费记录表里,银行卡号并不是主键或唯一键,
update cashView set userName='tony'where cardId='100000001';
例如A B两表各有字段ID列 如果视图已A.ID=B.ID进行表联接,当修改A表数据的时候则A于B关联,A表的数据应依赖于B表,因此此时的A表相当于子表,B表为主表,若B表不存在主键则无法修改数据;
对应的,如果修改B表数据的时候,B表依赖于A表,因此此时的B表相当于子表,A表为主表,因此要进行数据修改A表中必须存在主键
|