.Net程序员学用Oracle系列(8):触发器、作业、序列、连接

 
  • 1、触发器
  • 2、作业
    • 2.1、作业调度功能和应用
    • 2.2、通过 DBMS_JOB 来调度作业
  • 3、序列
    • 3.1、创建序列
    • 3.2、使用序列 & 删除序列
  • 4、连接
    • 4.1、创建连接
    • 4.2、使用连接 & 删除连接
  • 5、总结

1、触发器

可以把触发器看做是一种特殊的存储过程。触发器也是一种定义存放在数据字典中的模式对象,和存储过程一样,都包含声明和执行的 PL/SQL 块。触发器和存储过程最大的不同在于调用方式,存储过程是由用户或应用程序来调用和执行的,而触发器由 Oracle 系统来调用的,当触发事件发生时,触发器即被触发,然后隐式运行。

一般来说,在数据库项目中得慎用触发器,尽量少用,因为过度的使用触发器会导致项目难以维护,用不好还会影响应用程序性能。因此本文只简要介绍触发器,并处给出创建触发器的语法和一个示例。

创建触发器

语法:

CREATE OR REPLACE TRIGGER trigger_name
[BEFORE | AFTER] [INSERT | DELETE | UPDATE ] ON table_name
[FOR EACH ROW]
DECLARE
-- 定义变量
BEGIN
-- 触发器操作代码
END;

示例:

CREATE OR REPLACE TRIGGER trg_ai
AFTER INSERT ON demo.t_course
FOR EACH ROW
DECLARE
v_today DATE;
BEGIN
v_today := SYSDATE;
DBMS_OUTPUT.PUT_LINE('在 '||TO_CHAR(v_today,'yyyy-mm-dd')||' 添加了《'||:NEW.course_name||'》课程');
END;

测试:

INSERT INTO t_course(course_id,course_name,course_desc) VALUES(5,'C/C++','计算机专业课程');

删除触发器

DROP TRIGGER trg_ai; -- 删除名为 trg_ai 的触发器

2、作业

特殊说明:在上一版中,我将本节取名为任务,主要是本人之前看过的资料中大多将作业调度称之为任务,一开始我还纳闷儿呢,SQL Server 中好像是叫作业啊,难道 Oracle 又制造了一个独特而又不遵守业界规范的东西?后来看过官方手册才知道,原来是被国内网友带偏了!

我仔细想过这个中文名的问题,后来我觉得还是叫作业比较妥当一些。因为管理数据库是要完成大量任务的,决定何时何处完成任务是需要计划的,这些都是由 Oracle Scheduler 来调度和完成的,那么由调度程序创建的 JOB 叫任务或计划都不太合理,因为容易让人混淆,而作业似乎是一个比较贴切的称呼。

2.1、作业调度功能和应用

一般关系型数据库都提供了作业调度功能,Oracle 也提供了可用于 PL/SQL 的调度程序。调度程序使得数据库管理员和应用程序开发人员能够控制在数据库环境中何时何处发生各种任务。这些任务可以是耗时且复杂的,例如备份或夜间数据仓库加载和提取等,使有限的计算资源能够在竞争的作业中适当分配。

作业调度程序的最基本功能是能够安排作业在特定日期和时间或特定事件发生时运行。例如,需要让补丁应用于正在生产的数据库,为了尽量减少干扰,此任务需要在非高峰时段进行,当然可以让 IT人员在非高峰时段手动执行此任务;但为了降低运营成本,也可以使用作业调度程序轻松完成。

Oracle 先后提供了DBMS_JOBDBMS_SCHEDULER两个作业调度程序包,后者比前者功能更强大、定义更灵活、也增强了与系统的交互性。Oracle 也建议从DBMS_JOB切换到DBMS_SCHEDULER,但仍然支持DBMS_JOB以实现向后兼容,且作业调度程序包共享相同的作业协调器。

可以在命令窗口输入show parameter job_queue_processes查看数据库中定时任务的最多并发数,一般设置为 10,如果设为 0,那么数据库定时作业是不会运行的。更改并发数的方法是alter system set job_queue_processes=10

可以通过USER_JOBS视图来查询当前用户的作业调度情况。如下:

SELECT t.job jobno,t.what,to_char(t.next_date, 'yyyy-mm-dd hh24:mi:ss') next_date,t.interval FROM USER_JOBS t;

USER_JOBS视图各主要字段的含义说明,如下:

  • job:NUMBER 类型,任务的唯一编号。
  • what:VARCHAR2(4000),任务操作内容。
  • next_date:DATE 类型,下一次执行任务的时间。
  • interval:VARCHAR2(200),任务执行时间间隔。
  • log_user:提交任务的用户。
  • priv_user:赋予任务权限的用户。
  • schema_user:对任务作语法分析的用户模式。
  • last_date:最后一次成功运行任务的时间。
  • last_sec:如 hh24:mm:ss 格式的 last_date 日期的小时,分钟和秒。
  • this_date:正在运行任务的开始时间,如果没有运行任务则为 null。
  • this_sec:如 hh24:mm:ss 格式的 this_date 日期的小时,分钟和秒。

2.2、通过 DBMS_JOB 来调度作业

实际项目开发中,多数作业调度都会通过后台代码来完成,只有个别情况下会使用数据库中的作业调度功能。在 Oracle 10g 中,用DBMS_JOB来管理作业是比较方便的,接下来就详细说说如何使用DBMS_JOB

创建作业:

语法:

DBMS_JOB.SUBMIT(
job OUT BINARY_INTEGER,
what IN VARCHAR2, NEXT_DATE IN DATE DEFAULTSYSDATE,
[next_date] IN DATE,
[interval] IN VARCHAR2 DEFAULT 'NULL',
[no_parse] IN BOOLEAN DEFAULT FALSE,
[instance] IN BINARY_INTEGER DEFAULT ANY_INSTANCE,
[force] IN BOOLEAN DEFAULT FALSE
);

参数说明:

  • job:作业编号,输出参数,系统会自动分配,无法更改。
  • what:作业要完成的操作,如调用过程等。可通过DBMS_JOB.WHAT(job, what)来修改。
  • next_date:作业的下一次运行时间。可通过DBMS_JOB.NEXT_DATE(job,next_date)来修改。
  • interval:作业运行的时间间隔。可通过DBMS_JOB.INTERVAL(job,interval)来修改。

interval 参数设置案例

  • 每分钟(的0秒)执行一次:TRUNC(SYSDATE,''mi'') + 1/(24*60)
  • 每小时(的0分0秒)执行一次:TRUNC(SYSDATE,''hh24'') + 1/24
  • 每隔 7 天执行一次:TRUNC(SYSDATE) + 7 + 1/24
  • 每天凌晨两点执行一次:TRUNC(SYSDATE) + 1 + 2/24
  • 每周一凌晨 1 点执行一次:TRUNC(NEXT_DAY(SYSDATE,''monday'')) + 1/24
  • 每月 5 号凌晨 1 点执行一次:TRUNC(LAST_DAY(SYSDATE)) + 5 + 1/24
  • 每季度第一天凌晨 1 点执行一次:TRUNC(ADD_MONTHS(SYSDATE,3),''Q'') + 1/24
  • 每年 1 月 1 号凌晨 1 点执行一次:ADD_MONTHS(TRUNC(SYSDATE,''yyyy''),12) + 1/24
  • 不再运行该作业并删除它:NULL
  • 每星期六、星期日早上6点10分:TRUNC(LEAST(NEXT_DAY(SYSDATE, ''SATURDAY"), NEXT_DAY(SYSDATE, "SUNDAY")))+(6×60+10)/(24×60)

示例:

DECLARE
jobno NUMBER;
BEGIN
DBMS_JOB.SUBMIT(jobno, 'sp_sync_staff90;', SYSDATE, 'TRUNC(SYSDATE) + 1 + 2/24');
COMMIT;
END;

删除作业:

语法:

DBMS_JOB.REMOVE(job);

启用作业:

语法:

DBMS_JOB.RUN(job);

禁用作业:

语法:

DBMS_JOB.BROKEN(
job IN BINARY_INTEGER, -- 为 true 表示禁用任务,为 false 表示启用任务
broken IN BOOLEAN,
[next_date] IN DATE DEFAULT SYSDATE
);

示例:

BEGIN
DBMS_JOB.BROKEN(135,TRUE); -- 禁用 job 为 135 的任务
COMMIT;
END;

3、序列

可以把序列当成是数字工厂,因为它唯一的功能就是生产等间隔的数值。Oracle 中序列最典型的用法是生产主键的值。有 Oracle 开发经验的人应该都知道,Oracle 没有提供类似于 SQL Server 或 MySQL 中自动增长列的功能。如果需要使用自动增长列,则可以通过序列来实现类似功能。

我共参与过两个基于 Oracle 开发的项目,但都不用 Oracle 的序列(一个用 C# 代码生成序列号,另一个直接用 GUID),以至于到目前为止我都还没有使用序列的实战经验。下面只简单介绍下我所了解的序列。

3.1、创建序列

创建序列的标准语法如下:

CREATE SEQUENCE seq_name [INCREMENT BY n] [START WITH n]
[{MAXVALUE n/NOMAXVALUE}] [{MINVALUE n/NOMINVALUE}]
[{CYCLE/NOCYCLE}] [{CACHE n/NOCACHE}];

语法选项说明:

  • INCREMENT BY n:n 表示序列中连续两个值之间的间隔,也称作步长。如果 n 是正数则表示递增,如果 n 是负数则表示递减,默认是 1。
  • START WITH n:n 表示序列的起始值,即序列的第一个值,默认是 1,递增时 n 是 minValue,递减时 n 是 maxValue。
  • MAXVALUE n:n 表示序列的最大值,也可以选择 NOMAXVALUE,即不设置最大值,默认是 999999999999999999999999999。
  • MINVALUE n:n表示序列的最小值,也可以选择 NOMINVALUE,即不设置最小值,默认是 1。
  • CYCLE 和 NOCYCLE 分别表示当序列的值达到极限值后循环取值和不循环取值。
  • CACHE n:n 定义存放序列的内存块的大小,默认为 20(个数字)。NOCACHE 表示不对序列进行内存缓冲。将序列 CACHE(预先生成一部分序列号,放入到内存中)到内存中,可以加速对序列的访问。

3.2、使用序列 & 删除序列

使用序列

SELECT seq_name.CURRVAL FROM DUAL; -- 获得指定序列的当前值
SELECT seq_name.NEXTVAL FROM DUAL; -- 获得指定序列的下一个值

注意(有以下情况之一时不能使用序列):

  • 1、在 DELETE、SELECT、UPDATE 的子查询中。
  • 2、在视图或物化事物的查询中。
  • 3、SELECT 查询中使用了 DISTINCT 操作符。
  • 4、SELECT 查询中有 GROUP BY 或 ORDER BY。

如果想查询一下数据中到底有那些序列,语法如下:

SELECT * FROM USER_SEQUENCES; -- 当前用户所有序列

删除序列,示例:

DROP SEQUENCE seq_name;

4、连接

Oracle 中有个叫做 Database link 的东东,翻译成中文应该是数据库连接,为了称呼方便,下文统一称之为连接。在我跟公司一个技术专家对话时,对方提到“数据库连接”,于是我上网查了下:连接是定义一个数据库到另一个数据库的路径的对象,连接允许你查询远程表及执行远程程序。

连接有两种类型的,分别是公用的和私有的。一个公用数据库链接对于数据库中的所有用户都是可用的,而一个私有链接仅对创建它的用户可用。由一个用户给另外一个用户授权私有数据库链接是不可能的,一个数据库链接要么是公用的,要么是私有的。在任何分布式环境里,连接都是必要的。另外要注意的是连接是单向的连接。

4.1、创建连接

创建连接之前先得确定三件事,第一本地数据库和远程数据库之间的网络是可以正常连接的,第二创建连接的账号必须得有 CREATE DATABASE LINK 或 CREATE PUBLIC DATABASE LINK 的权限,第三用来登录到远程数据库的帐号必须得有 CREATE SESSION 权限。

实践告诉我,创建连接的正确语法如下:

CREATE [PUBLIC] DATABASE LINK dblink_name CONNECT TO user_name IDENTIFIED BY user_pwd USING 'connect_string';

其中connect_string有两种写法,示例:

示例(写法一):

CREATE PUBLIC DATABASE LINK dblink168
CONNECT TO office
IDENTIFIED BY 123456
USING '192.168.1.168:1521/orcl';

示例(写法二):

CREATE PUBLIC DATABASE LINK dblink168
CONNECT TO office
IDENTIFIED BY 123456
USING '(DESCRIPTION = (
ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.168)(PORT = 1521))
)(
CONNECT_DATA = (SERVICE_NAME = orcl)
)
)';

网上很多文章中给出的创建语法里都不包含指定密码这一项,还说如果不指定,则使用当前的用户名和口令登录到远程数据库,我反复实验了好多次,都是直接报语法错误。不过我倒是发现了一个特点,指定密码创建成功之后,再去查看连接定义的 SQL,会发现密码指令项不见了。我猜应该是 Oracle 做了特殊的加密处理,所以如果你要创建连接,不必担心显示指定密码后别人会看到,造成安全泄漏。

4.2、使用连接 & 删除连接

使用连接

我觉得连接真正的魅力之一便是使用方便,无论增删改查那种语句,只需要在表名后面跟上 @dblink_name 就能操作远程数据库了。如要查询 168 上用户表中女员工的数量,示例:

SELECT COUNT(1) FROM t_staff@dblink168 t WHERE t.gender=0;

测试中我也发现一个小问题,假如我要查询 168 上的服务器时间,按理说写法应该如下:

SELECT SYSDATE FROM DUAL@dblink168; -- 结果显示出来的时间仍是本地数据库的服务器时间

如果为了命名更加统一,或者不想让对方知道 dblink 的名字,也可以通过视图或同义词包装一下,示例:

CREATE VIEW v_name AS SELECT * FROM table_name@dblink_name;
CREATE SYNONYM table_name FOR table_name@dblink_name;

跟连接有关的几个视图,介绍如下:

SELECT * FROM DBA_DB_LINKS; -- 查询当前数据库实例中所有 dblink
SELECT * FROM V$DBLINK; -- 查询当前数据库示例中正在打开状态的 dblink
SELECT * FROM USER_SYS_PRIVS t WHERE t.privilege LIKE '%LINK%'; -- 查询跟 dblink 有关的系统权限

删除连接

对于非 PUBLIC 类型的连接,只有 owner 自己才能删除,非 PUBLIC 类型的连接没有这个要求。删除连接的示例:

DROP [PUBLIC] DATABASE LINK dblink168;

5、总结

本文主要介绍了 Oracle 中相对不那么常用的一些对象的 SQL 操作,但在实际做项目过程中,有时候它们又非常实用,所以有必要总结一下,以免用到的时候不记得语法,还得去查资料。

Oracle系列:触发器、作业、序列、连接的更多相关文章

  1. Oracle系列十四 序列、索引和同义词

    序列 : 提供有规律的数值.索引  : 提高查询的效率同义词  :给对象起别名 序列: 可供多个用户用来产生唯一数值的数据库对象 自动提供唯一的数值 共享对象 主要用于提供主键值 将序列值装入内存可以 ...

  2. .Net程序员学用Oracle系列(8):触发器、作业、序列、连接

    1.触发器 2.作业 2.1.作业调度功能和应用 2.2.通过 DBMS_JOB 来调度作业 3.序列 3.1.创建序列 3.2.使用序列 & 删除序列 4.连接 4.1.创建连接 4.2.使 ...

  3. .Net程序员学用Oracle系列(8):触发器、任务、序列、连接

    <.Net程序员学用Oracle系列:导航目录> 本文大纲 1.触发器 1.1.创建触发器 1.2.禁用触发器 & 启用触发器 & 删除触发器 2.任务 2.1.DBMS_ ...

  4. .Net程序员学用Oracle系列(25):触发器详解

    1.触发器理论 1.1.触发器的应用场景 1.2.触发器的类型 1.3.DML 触发器的触发顺序 2.触发器实战 2.1.创建触发器 2.1.1.创建 DML 触发器 2.1.2.创建 DDL 触发器 ...

  5. oracle 触发器,序列,索引

    oracle 触发器,序列,索引 --1,触发器 ----trigger /*触发器是一种特殊的存储过程,它与数据表紧密联系,用于保护表中的数据, 当一个定义了特定类型触发器的基表执行插入.修改或删除 ...

  6. .Net程序员学用Oracle系列(7):视图、函数、存储过程、包

    1.视图 1.1.创建.删除及调用普通视图 1.2.高级视图介绍 2.函数 2.1.系统函数介绍 2.2.创建.删除及调用自定义函数 3.存储过程 3.1.创建.修改及删除存储过程 3.2.调用存储过 ...

  7. .Net程序员学用Oracle系列(7):视图、函数、过程、包

    <.Net程序员学用Oracle系列:导航目录> 本文大纲 1.视图 1.1.创建视图 2.函数 2.1.创建函数 2.2.调用函数 3.过程 3.1.创建过程 3.2.调用过程 4.包 ...

  8. .Net程序员学用Oracle系列(24):数据字典、死锁

    1.静态数据字典 1.1.实用静态数据字典 1.2.运用静态数据字典 2.动态数据字典 2.1.实用动态性能视图 2.2.运用动态性能视图 3.死锁 3.1.定位死锁 3.2.解锁方法 3.3.强制删 ...

  9. 【转】Oracle系列导航目录

    .Net程序员学用Oracle系列(1):导航目录 .Net程序员学用Oracle系列(2):准备测试环境 .Net程序员学用Oracle系列(3):数据库编程规范 .Net程序员学用Oracle系列 ...

随机推荐

  1. React手稿之 React-Saga

    Redux-Saga redux-saga 是一个用于管理应用程序副作用(例如异步获取数据,访问浏览器缓存等)的javascript库,它的目标是让副作用管理更容易,执行更高效,测试更简单,处理故障更 ...

  2. poj_1995 Raising Modulo Numbers (快速幂)

    [题目链接] http://poj.org/problem?id=1995 [算法] 基本快速幂(二进制思想) 注意两个int相乘可能溢出,加(long long)但是相乘不要加括号,不然会先溢出在类 ...

  3. P3064 [USACO12DEC]伊斯坦布尔的帮派 (模拟)

    题目传送门 题意: 一片草地,每次可以只可以让一种牛占领,问你怎样安排牛的次序 最后剩下的是1号牛,并且输出其数量 思路: 看到n到100 ,所以可以(n^3)暴力,第一重遍历次序,第二枚举是哪只牛 ...

  4. LeetCode103. 二叉树的锯齿形层次遍历

    103. 二叉树的锯齿形层次遍历 描述 给定一个二叉树,返回其节点值的锯齿形层次遍历.(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行). 示例 例如,给定二叉树: [3,9,2 ...

  5. ORACLE之字符集修改(10g)

    当从oracle服务器将数据导出成dmp文件后,再导入到本地的oracle数据库时,出现: IMP-00019: 由于 ORACLE 错误 12899 而拒绝行 IMP-00003: 遇到 ORACL ...

  6. 行人重识别(ReID) ——数据集描述 CUHK03

    数据集简介 CUHK03是第一个足以进行深度学习的大规模行人重识别数据集,该数据集的图像采集于香港中文大学(CUHK)校园.数据以"cuhk-03.mat"的 MAT 文件格式存储 ...

  7. git恢复彻底删除的分支

    由于一时疏忽,错误的删除了未发布正式的开发分支,经查资料已恢复分支,特此记录 查看Git日志 git reflog |grep 'filter_or_gwf' 以下日志为已删除分支 filter_or ...

  8. python 简易小爬虫

    此脚本用于爬站点的下载链接,最终输出到txt文档中. 如果是没有防盗链设置的站点,也可以使用脚本中的下载函数尝试直接下载. 本脚本是为了短期特定目标设计的,如果使用它爬其它特征的资源链接需自行修改配置 ...

  9. Nginx的反向调度功能

    1.案例实现Nginx反向代理; 2.反向代理的理论知识拓展. 一, 实验Nginx的反向代理功能 使用Nginx实现Web反向代理功能,实现如下功能: 后端Web服务器两台,可以使用httpd实现 ...

  10. basename 显示文件名或目录名

    1. 命令功能 basename 显示文件名或目录名,不显示文件的全路径文件名 2. 语法格式 basename  文件路径名 3. 使用范例 [root@localhost data]# basen ...