`
chenniaoc
  • 浏览: 39881 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

OracleのトリガでJavaの処理を起動する

阅读更多
OracleのトリガでJavaの処理を起動する

JavaとPL/SQLを組み合わせて開発していると、「OracleのトリガでJavaの処理を起動させたいな」という局面に出会うことがあります。単にJavaで書いたプログラムを動かしたいだけならば、OracleのトリガそのものをJavaで書くということもできるし、そもそもPL/SQL で大概のことが済んでしまいます。そうではなく、特定の実行空間(サーブレット実行環境)などで、スタティック変数やスレッドなどにアクセスしたいというような場合が、この文書のテーマです。私の場合、マスタテーブルをスタティック変数の配列に読み込んで利用しているのですが、そのマスタテーブルを SQL*PlusやAccessで変更した場合に配列を再読み込みさせたい、という問題にぶつかりました。
このような場合、一定間隔でテーブルをチェックする、ということになりがちですが、そのためのシステム負荷は馬鹿になりません。なんとかトリガを上手く使ったスマートな方法を取りたいところです。
DBMS_ALERTパッケージ

いろいろ調べたところ、Oracleの標準PL/SQLパッケージ "DBMS_ALERT" をトリガと組み合わせて使う方法が定番だろうということが分かりました。このDBMS_ALERTパッケージは、メッセージを非同期に送受信する機能をまとめたパッケージで、これによってアプリケーションの通信が可能になります。"DBMS_ALERT"は実際にはテーブルアクセスを行いませんので、データベースへの負荷はほぼ気にする必要はありません。もちろん、ポーリングを行なうわけではないのでシステム負荷もわずかです。

Javaとトリガの連携での具体的な利用法は、実行空間の中でメッセージの受信とそれに伴う処理を行なうスレッドを走らせておき、表の更新時にメッセージの送信を行うようなトリガを作成する、ということになります。
サンプルコード

ここでは、マスタ表 "PLACE"と"TEAM"の変更を検出し、それに対応した処理を行なうような例を取り上げます。

まず、DBMS_ALERTパッケージが利用できるように、SYSユーザでログインして実行DBユーザにDBMS_ALERTのEXECUTE権限を与えておく必要があります。
次に、"PLACE"と"TEAM"が変更になった際にDBMS_ALERTのアラートを送信するようなトリガを作成します。そのためのSQL文は以下のようになります。

CREATE OR REPLACE TRIGGER T_CHGTEAM AFTER INSERT OR UPDATE OR DELETE ON TEAM
    BEGIN
        DBMS_ALERT.SIGNAL('TEAM','UPDATED!');
    END;
/
CREATE OR REPLACE TRIGGER T_CHGPLACE AFTER INSERT OR UPDATE OR DELETE ON PLACE
    BEGIN
        DBMS_ALERT.SIGNAL('PLACE','UPDATED!');
    END;
/

DBMS_ALERT.SIGNALの一つ目の引数がアラートの名前、二つ目の引数がメッセージの内容になります(ここではメッセージの内容は利用しません)。

続いて、このALERTを受け取るJavaプログラムを作成します。スレッド廻りの部分を書くと長くなりますので、ここではアラートの受け取り部分だけを記述します。プログラム全体はダウンロードして眺めてください(TableWatchDog.java)。

/**
* マスタテーブルの開始を監視する
*/
public void run() {
    String dicttype;
    try {
        Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
        String url = "jdbc:oracle:thin:@localhost:1521:orcl";
        Connection con = DriverManager.getConnection(url, "test", "test");

         // DBMS_ALERT.REGISTER
         //   - 指定した名前のアラートをこのセッションで受け取ることを定義する
        String storedproc = "{call DBMS_ALERT.REGISTER(?)}";
        CallableStatement cstmt1 = con.prepareCall(storedproc);
        cstmt1.setString(1, "TEAM");
        cstmt1.executeUpdate();
        cstmt1.setString(1, "PLACE");
        cstmt1.executeUpdate();

         // DBMS_ALERT.WAITANY
         //   - メッセージの受信待ち
         //     ここでは、一つの待ちプロセスで複数の種類のメッセージを受け取り、
         //     メッセージの内容で処理を分ける。
        storedproc = "{call DBMS_ALERT.WAITANY(?,?,?,?)}";
        cstmt2 = con.prepareCall(storedproc);
         // 第1パラメータ(OUT) - アラートの名前
        cstmt2.registerOutParameter(1, Types.VARCHAR);
         // 第2パラメータ(OUT) - メッセージの内容
        cstmt2.registerOutParameter(2, Types.VARCHAR);
         // 第3パラメータ(OUT) - 実行結果。0ならアラート受信。1ならタイムアウト。
        cstmt2.registerOutParameter(3, Types.INTEGER);
         // 第4パラメータ(IN)  - タイムアウト時間(秒数)
        cstmt2.setInt(4, 300);
        System.err.println("WAIT START!");

         // stopSyncが実行されると completeフラグがセットされる。
         // それまでは無限ループとなる。
        while (complete == false) {
            try {
                 // アラートはトランザクションがコミットした時点で送受信される
                con.commit();
                 // 上で指定したDBMS_ALERT.WAITANYプロシジャの実行
                cstmt2.executeUpdate();
                if (cstmt2.getInt(3) == 1) {
                     //タイムアウトによって終了した場合の処理
                    System.err.println("TABLES NO UPDATED!");
                } else {
                     //アラート受信で終了した場合、アラートの名前で処理を分ける
                    dicttype = cstmt2.getString(1);
                    if (dicttype.equals("TEAM") == true) {
                         // チーム配列の初期化処理がここに入る
                        System.err.println("TEAM TABLE UPDATED!");
                    }
                    if (dicttype.equals("PLACE") == true) {
                         // 地名配列の初期化処理がここに入る
                        System.err.println("PLACE TABLE UPDATED!");
                    }
                }
            } catch (SQLException e) {
                e.printStackTrace();
                break;
            }
        }
       
         // DBMS_ALERT.REGISTER
         //   - 指定した名前のアラート受信定義をこのセッションから削除する
        storedproc = "{call DBMS_ALERT.REMOVE(?)}";
        CallableStatement cstmt3 = con.prepareCall(storedproc);
        cstmt3.setString(1, "TEAM");
        cstmt3.executeUpdate();
        cstmt3.setString(1, "PLACE");
        cstmt3.executeUpdate();

        con.commit();
        con.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

なお、待機している間、つまりほぼ動作中ずっとコネクションを一つ掴んだままになります。サーブレットなどでスレッドプールを使える場合でも、このスレッド用にはプールのコネクションを割り当てないほうが良いでしょう。
分享到:
评论

相关推荐

    Oracle Database の移行 - 概要編

    - **パフォーマンスの改善**:より高速なクエリ処理やデータ転送が可能です。 - **セキュリティの強化**:データ保護とプライバシーに関する新しいオプション。 - **管理の容易さ**:自動化された管理タスクと高度な...

    Boot-Campカリキュラム概要 (新人用)1

    【新人用】Boot-Campカリキュラム概要は、新入社員向けの社内教育プログラムであり、1か月目...K12、Java、Oracle、SQL、およびDBAに関する知識を基盤として、新入社員はIT分野での専門性を確実に築くことができます。

    java连接oracle数据库jar包

    Java连接Oracle数据库主要依赖于JDBC(Java Database Connectivity)技术,这是Java平台中用于与各种数据库进行交互的一套标准API。Oracle公司提供了JDBC驱动,使得Java程序能够方便地访问Oracle数据库。在Java中...

    安全SQL的呼出方法

    - **2.5.1 文字列リテラルに対するSQLインジェクション**:ユーザー入力に含まれるシングルクォートや特殊文字がエスケープされない場合、SQL文の意味が変化し、予期しない結果を引き起こす可能性があります。...

    java 连接oracle12c 的jar包

    在Java编程环境中,连接Oracle 12c数据库是常见的需求,尤其在开发企业级应用时。Oracle 12c是Oracle公司推出的最新版本的数据库管理系统,提供了许多性能优化和高级特性。然而,为了使Java应用程序能够顺利地与...

    用java编程将txt文件数据导入oracle

    "Java编程将TXT文件数据导入Oracle数据库" Java 编程将 TXT 文件数据导入 Oracle 数据库是指使用 Java 语言编写程序将 TXT 文件中的数据导入 Oracle 数据库中,以方便进行计算、统计等操作。下面将详细介绍该知识...

    Java导出Oracle数据库数据

    Java 导出 Oracle 数据库数据 Java 是一种流行的编程语言,广泛应用于各种领域。Oracle 是一种关系数据库管理系统,广泛应用于企业级应用中。在实际项目中,数据备份和恢复是非常重要的工作。本文将介绍如何使用 ...

    Java连接Oracle数据库驱动(各种版本)

    Java classes when using the JDBC Thin and OCI client-side driver - with Java 7.0 VM. ojdbc6.jar Java classes when using the JDBC Thin and OCI client-side driver - with Java 6.0 VM. ojdbc5.jar Java ...

    Java操作Oracle数据库(建表,插数据,删除)

    Java 操作 Oracle 数据库(建表,插数据,删除) Java 是一种广泛使用的编程语言,而 Oracle 数据库是一种功能强大且广泛使用的关系型数据库管理系统。在本文中,我们将探讨如何使用 Java 操作 Oracle 数据库,包括...

    java代码oracle数据库批量插入

    ### Java代码实现Oracle数据库批量插入的关键知识点 #### 1. JDBC连接配置 - **JDBC URL**: `jdbc:oracle:thin:@IP:1521:orcl`,这里的URL指定了连接到Oracle数据库的方式。其中`@IP:1521:orcl`中的IP是指数据库...

    JAVA Oracle_JDBC

    JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。

    java连接oracle的jar包

    Java连接Oracle数据库主要依赖于Oracle提供的JDBC驱动,也称为ojdbc.jar包。这个驱动程序使得Java应用程序能够通过Java Database Connectivity (JDBC) API与Oracle数据库进行交互。Oracle JDBC驱动有多种类型,如 ...

    ORACLE 10G java 驱动包

    Oracle 10G Java驱动包是Oracle数据库与Java应用程序交互的重要组成部分,主要包含两个关键的JAR文件:`classes12.jar` 和 `ojdbc14.jar`。这两个文件为Java开发者提供了连接Oracle 10G数据库的必要工具,使得在Java...

    连接Oracle例子--Java

    在Java编程环境中,连接Oracle数据库是一项基础且重要的任务。Oracle是全球知名的关系型数据库管理系统,广泛应用于企业级应用。本文将详细介绍如何使用Java通过JDBC(Java Database Connectivity)API来建立与...

    个人亲测oracle触发器调用java程序

    Oracle触发器调用Java程序 Oracle触发器是Oracle数据库中的一种机制,可以在数据库中执行特定的操作。在本文中,我们将介绍如何使用Oracle触发器调用Java程序。 一、加载Java程序 首先,我们需要将Java程序加载到...

    日语面试题总结(IT方面)

    また、Javaに関する具体的な問題に対するソリューションを見つけるためには、Stack Overflowなどのコミュニティサイトも活用しました。 --- #### 问题5: 一(ͤ)餤ไหน(٤礦)gorf學一B **问题分析:** 这个问题...

    使用java实现oracle存储过程

    使用java实现oracle存储过程。 共有3个小例子。实现的功能 1、无返回值的存储过程 如 insert 2、有返回值的存储过程(非列表)select id from tab 3、返回列表 如:select * from tab 顺便鄙视下csdn,作为一个it...

    oracle课程设计—基于java的学生成绩管理系统

    Oracle课程设计—基于Java的学生成绩管理系统是一个典型的IT项目,涵盖了数据库管理和后端编程等多个技术领域。在这个项目中,学生通常会学习如何利用Oracle数据库存储和管理学生成绩,以及如何使用Java作为编程语言...

    java连接oracle数据库驱动

    java连接oracle数据库驱动器java连接oracle数据库驱动器java连接oracle数据库驱动器java连接oracle数据库驱动器java连接oracle数据库驱动器java连接oracle数据库驱动器java连接oracle数据库驱动器java连接oracle...

    oracle 在java中的事务处理和异常回滚。

    在Java编程中,Oracle数据库是常用的后端存储系统,而事务处理和异常回滚是确保数据一致性、完整性和可靠性的关键机制。以下是对这个主题的详细讲解。 首先,Oracle JDBC驱动程序是Java与Oracle数据库之间通信的...

Global site tag (gtag.js) - Google Analytics