基于Oracle plsql的多线程编程架构 (附存储过程)

简介:
作者介绍

冯守东北京科讯华通科技发展有限公司高级项目经理。超12年Oracle开发及管理经验,多年运营商和政府企业级系统运维经验,曾获得东软最佳设计方案奖。熟悉Weblogic、TUXEDO、IBM WAS等相关中间件运维。熟悉MySQL、DB2、Informix等其他开源或商业数据,以及Openstack、Hadoop相关生态系统、网站架构设计等。

 

  引言  

 

1  文档编制目的

 

在日常编程范围内有很多大计算量的存储过程,在业务系统中使用Java实现多线程往往会有参与计算的任务不能均匀分配、不能完全发挥数据库服务器的高端性能,代码实现起来门槛较高,比较麻烦。因此,本文档将通过DIY方式介绍如何在Oracle数据库服务器实现存储过程的并行处理。

 

 

2  背景

 

  • 有一个很大的计算过程,参与计算的对象非常多。例如数据固化、应收核定等。

  • 要用PL/SQL逐行处理,当然这这样做会有大量的读取和DML操作。

  • 我们使用一台多CPU的数据库服务器,并且有大量磁盘空间。

  • 我们发现操作系统/SQL并不是非常容易扩展的,它只使用了1个CPU,并没有利用整个机器。

  • 由于我们使用固有的单线程程序来处理数据,ORACLE并行查询不可用!

  • “一个人的活多个人做”并行处理,将固有的任务/数据分解成N个不重叠的组,同时开始PL/SQL子程序N个拷贝。

 

3  范围

 

本文档适用于所有使用Oracle 10g的项目,系统吞吐量大,有一定执行时间限制的应用场合。

 

4  词汇表

 

词汇名称

词汇含义

备注

DBMS_SCHEDULER

Oracle任务调度器

只有Oracle 10g支持新特性

READ LOCK

Oracle行排他锁

Oracle 任何版本

Autonomous Transactions

Oracle自治事务

Oracle 任何版本

Dynamic SQL

Oracle 动态SQL

Oracle 任何版本

 

 

总体架构设计

  

 

1 

设计原则和方法

 

原则:

 

  1. 提供一个脱离业务、通用性强的功能组件。

  2. 易于复用,代码修改少,可配置满足不同要求。

  3. 对控制重复执行有所考虑。

  4. 组件提供人性化的客户交互界面,解决进度情况展示的问题。

  5. 能有一个实现和效率之间的平衡。

 

方法:

 

此组件中的并行执行遵循了几乎相同的逻辑。通常可以将某个大“任务”划分为较小的部分,并且并发地执行各个部分。例如,如果需要计算一大批结果并把数据保存到数据库中,那么完全可以建立4 个或更多并行会话(P001~P004)来一起执行存储过程,任务的分派有一个任务分派器来做,分派器可以按照每个进程的负载情况均匀的分派任务。每个会话分别调用预定义的业务过程来执行分派器分派的任务。当需要提交处理结果的时候,可以在每个业务过程内进行保存。

 

此组件作为一种实现架构,可以使一些要求吞吐量大、执行效率高的的操作得到大幅改善,使其能够呈数量级提高。由于此架构对系统资源要求较高,通常情况下应该在非高峰期而且有足够资源的情况下之用。

 

2  系统整体架构

 

20170103074933450.png

 

3  系统级组件

 

DBMS_SCHEDULER是Oracle 10G中新增的一个包,与老版本的DBMS_JOB包相比,DBMS_SCHEDULER有很多新特性。Oracle 10g引入DBMS_SCHEDULER来替代先前的DBMS_JOB,在功能方面,它比DBMS_JOB提供了更强大的功能和更灵活的机制。

 

DBMS_JOB这个程序包存在的问题是它只能够处理 PL/SQL 代码段,即仅能处理匿名程序块和存储程序单元。它不能在数据库外部处理操作系统命令文件或可执行文件中的任何东西。 

 

为此,您将不得不求助于操作系统调度实用工具。另外DBMS_JOB所生成任务进程一旦生成就在数据库中一直有效,不能在任务结束后自动终止。

 

DBMS_SCHEDULE是直接在数据库内部的一个作业调度实用程序,强大到足够处理所有类型的作业,而不只是 PL/SQL 代码段。它可以在处理任务执行结束后自动终止。最好的一点是它是数据库自带的,无需任何额外的成本,这样我们在实现上直接使用即可。

 

4  流程图各部分说明

 

  • 前台用户:主要是进行程序调度,主要是任务是把我程序执行时机。

 

  • 任务列表:通过一个普通表实现,该表中主要包括了业务过程执行过程中所需要的入参,参数的形式为‘|’分隔的字符串。同时附加了异常及进度信息。该表是由程序开发人员根据具体的业务定义结构并生成入参数据。

 

  • 进程控制:根据系统参数或业务参数调用DBMS_SCHEDULER生成对应个数的服务进程。依据当前进程执行情况,控制任务的重复执行。当出现紧急情况时终止所有服务进程。

 

  • 任务读取:通过ORACLE的自制事务及锁特性,实现任务读取的一致性,即每次服务进程处理一行任务数据的时候,不被其它的服务进程重复读取。

 

  • 业务过程:该部分同样由程序开发人员根据具体业务类型开发存储过程。该过程根据传入的过程名称和参数个数动态调用业务存储过程。

 

  • 服务进程:ORACLE自动管理的进程,服务进程的数量取决于“进程控制”创建的进程数。服务进程主要工作1、通过“任务读取”获得“业务过程”的入参。2、调用“业务过程”生成业务数据。

 

  • 数据存储:业务过程处理之后生成的结果。

 

  • 进程监视:“前台用户”调用之后任务执行的监控,包括正在执行情况及最终执行结果。

 

  系统接口设计  

 

1  程序开发接口设计

 

此组件向开发人员公布3个系统接口,1个调试接口。

 

 

  • PKG_多线程服务.PRC_进程控制

 

入参:

PRM_PROGRAM   即要调用的业务过程名称。

PRM_PARMCOUNT 即对应业务过程的参数个数

 

  • PKG_多线程服务.PRC_进程停止

 

直接终止后台正在运行的多线程服务。

 

  • PKG_多线程服务.PRC_调试使用

 

入参:

PRM_PROGRAM   即要调用的业务过程名称。

PRM_PARMS      即对应业务过程的参数字符串。

 

因为是动态调用存储过程,所以SC01中的参数个数必须同业务过程个数严格对应,提供此方法主要是让开发人员调试使用。

 

  • 任务列表SC01

 

开发人员要压入的任务,即业务过程的参数。参数必须以‘|’分隔,并且保证在多线程服务运行的过程中,其他模块不能对SC01进行DML操作,为实现其他模块不能操作SC01,在任何DML操作之前必须执行一个语句如下:

 

SELECTCOUNT(*)

      INTO N_EXISTS

      FROM USER_SCHEDULER_JOBSS

     WHERE S.STATE = 'RUNNING'

AND S.JOB_ACTION = 'PKG_多线程服务.PRC_服务进程';

 

综上所述执行一个ORACLE多线程服务,开发人员只需要做一项工作即压入正确SC01参数,然后直接调用即可。

 

2  用户展示接口设计

 

前台查询SC02、SC03视图

 

  数据库结构设计  

 

1  数据表设计

 

描述:模块任务分派表Sc01

 

20170103074952198.png

 

2  视图设计

 

 

  • 描述:运行监视试图Sc02

 

CREATE OR REPLACE VIEW SC02 AS

SELECT S.JOB_CREATOR        现场创建用户,

      S.JOB_NAME            线程名称,

      S.JOB_ACTION          过程名称,

      S.last_start_date           启动时间,

      S.COMMENTS           备注,

      (SELECT COUNT(*)

         FROM SC01

        WHERE THREAD_NAME = lower(S.JOB_NAME)

          AND STATUS = '0') 未处理数,

      (SELECT COUNT(*)

         FROM SC01

        WHERE THREAD_NAME = lower(S.JOB_NAME)

          AND STATUS = '1') 运行成功数,

      (SELECT COUNT(*)

         FROM SC01

        WHERE THREAD_NAME = lower(S.JOB_NAME)

          AND STATUS = '-1') 运行失败数

 FROM USER_SCHEDULER_JOBS S

 ORDERBY S.JOB_NAME;

  

  • 描述:运行结果监视试图sc03

 

CREATE OR REPLACE VIEW SC03 AS

SELECT S.OWNER             用户名,

      S.JOB_NAME          线程名称,

      S.STATUS            线程状态,

      S.LOG_DATE          日志时间,

      S.ACTUAL_START_DATE 线程实际运行时间,

      S.RUN_DURATION      线程持续运行时间,

      S.SESSION_ID        会话ID,

      S.SLAVE_PID         进程ID,

      S.ADDITIONAL_INFO   线程备注信息,

      (SELECT COUNT(*) FROM Sc01 WHERE thread_name = lower(S.JOB_NAME) ANDstatus = '0') 未处理数,

      (SELECT COUNT(*) FROM Sc01 WHERE thread_name = lower(S.JOB_NAME) ANDstatus = '1') 运行成功数,

      (SELECT COUNT(*) FROM Sc01 WHERE thread_name = lower(S.JOB_NAME) ANDstatus = '-1')运行失败数

 FROM USER_SCHEDULER_JOB_RUN_DETAILS S

 ORDER BY S.JOB_NAME;

 

3  数据安全性

 

所需要系统的权限如下:

grant manage scheduler to AHSIMIS;

grant create any job to AHSIMIS;

 

  尚需解决的问题  

 

如果是RAC环境,程序尚不能跨实例运行。

原文发布时间为:2017-01-03

本文来自云栖社区合作伙伴DBAplus

相关文章
|
16天前
|
Java 开发者
Java面试题:请解释内存泄漏的原因,并说明如何使用Thread类和ExecutorService实现多线程编程,请解释CountDownLatch和CyclicBarrier在并发编程中的用途和区别
Java面试题:请解释内存泄漏的原因,并说明如何使用Thread类和ExecutorService实现多线程编程,请解释CountDownLatch和CyclicBarrier在并发编程中的用途和区别
18 0
|
18天前
|
安全 Python
告别低效编程!Python线程与进程并发技术详解,让你的代码飞起来!
【7月更文挑战第9天】Python并发编程提升效率:**理解并发与并行,线程借助`threading`模块处理IO密集型任务,受限于GIL;进程用`multiprocessing`实现并行,绕过GIL限制。示例展示线程和进程创建及同步。选择合适模型,注意线程安全,利用多核,优化性能,实现高效并发编程。
28 3
|
18天前
|
缓存 Java 调度
Java并发编程:深入解析线程池与Future任务
【7月更文挑战第9天】线程池和Future任务是Java并发编程中非常重要的概念。线程池通过重用线程减少了线程创建和销毁的开销,提高了资源利用率。而Future接口则提供了检查异步任务状态和获取任务结果的能力,使得异步编程更加灵活和强大。掌握这些概念,将有助于我们编写出更高效、更可靠的并发程序。
|
2天前
|
监控 Java 开发者
深入理解Java并发编程:线程池的原理与实践
【5月更文挑战第85天】 在现代Java应用开发中,高效地处理并发任务是提升性能和响应能力的关键。线程池作为一种管理线程的机制,其合理使用能够显著减少资源消耗并优化系统吞吐量。本文将详细探讨线程池的核心原理,包括其内部工作机制、优势以及如何在Java中正确实现和使用线程池。通过理论分析和实例演示,我们将揭示线程池对提升Java应用性能的重要性,并给出实践中的最佳策略。
|
3天前
|
安全 Java 数据处理
Java并发编程:线程同步与协作的深度解析
在探索Java并发编程的海洋中,线程同步与协作的灯塔指引着航向。本文将深入挖掘线程同步机制的核心原理,揭示锁、条件变量等工具如何确保数据的一致性和线程间有序的通信。通过案例分析,我们将解码高效并发模式背后的设计哲学,并探讨现代Java并发库如何简化复杂的同步任务。跟随文章的步伐,您将获得提升多线程应用性能与可靠性的关键技能。 【7月更文挑战第24天】
17 5
|
2天前
|
算法 调度
什么是无锁化编程?线程模型有哪些类型
什么是无锁化编程?线程模型有哪些类型
9 2
|
5天前
|
监控 Java
Java并发编程:深入理解线程池
在Java并发编程领域,线程池是提升应用性能和资源管理效率的关键工具。本文将深入探讨线程池的工作原理、核心参数配置以及使用场景,通过具体案例展示如何有效利用线程池优化多线程应用的性能。
|
13天前
|
安全 Java 开发者
Java并发编程中的线程安全性与性能优化
在Java编程中,处理并发问题是至关重要的。本文探讨了Java中线程安全性的概念及其在性能优化中的重要性。通过深入分析多线程环境下的共享资源访问问题,结合常见的并发控制手段和性能优化技巧,帮助开发者更好地理解和应对Java程序中的并发挑战。 【7月更文挑战第14天】
|
13天前
|
监控 Java API
Java并发编程之线程池深度解析
【7月更文挑战第14天】在Java并发编程领域,线程池是提升性能、管理资源的关键工具。本文将深入探讨线程池的核心概念、内部工作原理以及如何有效使用线程池来处理并发任务,旨在为读者提供一套完整的线程池使用和优化策略。
|
15天前
|
存储 安全 算法
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第72天】 在现代软件开发中,尤其是Java应用开发领域,并发编程是一个无法回避的重要话题。随着多核处理器的普及,合理利用并发机制对于提高软件性能、响应速度和资源利用率具有重要意义。本文旨在探讨Java并发编程的核心概念、线程安全的策略以及性能优化技巧,帮助开发者构建高效且可靠的并发应用。通过实例分析和理论阐述,我们将揭示在高并发环境下如何平衡线程安全与系统性能之间的关系,并提出一系列最佳实践方法。

推荐镜像

更多