Es wurde eine Reparaturanforderung gestellt, um das Protokoll der Tabelle auszugeben, die von der intern entwickelten Anwendung und der zugehörigen Tabelle verwendet wurde. Lesen Sie das Protokoll, damit eine andere externe Anwendung Informationen ausgibt. Der Zeitpunkt für die Ausgabe des Protokolls war, als die Anwendung die Daten in der Tabelle registrierte. In diesem Fall hatte ich das Gefühl, dass es möglich sein würde, einen Stapel mithilfe eines Datenbank-Triggers auszuführen, ohne die Anwendung zu ändern, und entschied mich daher, dies zu untersuchen. Ich möchte die Anwendung nicht so stark wie möglich ändern.
Es gibt zwei Möglichkeiten, einen Windows-Stapel aufzurufen.
Wenn Sie nur die Protokolldatei ausgeben möchten, können Sie das Paket UTL_FILE oder das Paket java.io auf Java verwenden. Angesichts der Vielseitigkeit des Speicherns auf einem Netzlaufwerksziel ist es jedoch besser, es an dem Ziel zu verarbeiten, das den Windows-Stapel aufgerufen hat. Etwas ist bequem. Referenz: Überlegen Sie, wie Protokolle aus PL / SQL ausgegeben werden
Oracle hat eine Java-VM implementiert, mit der Java-Programme in der Datenbank ausgeführt werden können. Ich habe bisher nur PL / SQL verwendet, daher ist dies eine gute Gelegenheit, gespeichertes Java zu lernen.
Ich verwies auf die Website von "Java in PL / SQL verwendet".
Sobald Sie ein gespeichertes Java erstellt haben, müssen Sie auch einen Wrapper erstellen, um es aufzurufen. Der Wrapper muss nur einmal erstellt werden, wenn sich das Argument oder der Rückgabewert nicht ändert. Das Ergebnis wird auch dann wiedergegeben, wenn der gespeicherte Inhalt von Java später neu geschrieben wird.
CREATE OR REPLACE JAVA SOURCE NAMED java_test_src
AS
public class Test {
public static int kasan(int a,int b){
return a+b;
}
}
/
CREATE OR REPLACE FUNCTION kasanf(a in number,b in number)
RETURN NUMBER
IS LANGUAGE java
NAME 'Test.kasan(int,int) return int'
;
/
Es kann genauso verwendet werden wie das Aufrufen einer PL / SQL-Benutzerfunktion. Interessant.
SELECT kasanf(2,3) FROM DUAL;
KASANF(2,3)
-----------
5
Führen Sie einen Windows-Stapel (test.bat) aus, indem Sie ein Argument mit der Methode Runtime.getRuntime (). Exec übergeben, die einen Befehl von Java aus ausführt.
CREATE OR REPLACE JAVA SOURCE NAMED PLSQLExecByJava
AS
public class PLSQLExecByJava {
public static String execByJava(
String key
) {
try {
String cmd = "cmd /c start C:\\foo\\test.bat " + key;
Runtime.getRuntime().exec(cmd);
return "Success";
} catch(Exception e) {
return e.getMessage();
}
}
}
/
CREATE OR REPLACE FUNCTION FuncExec(key in VARCHAR2)
RETURN VARCHAR2
IS LANGUAGE java
NAME 'PLSQLExecByJava.execByJava(java.lang.String) return java.lang.String'
;
/
Wenn Sie Befehle ausführen oder Dateien in einer gespeicherten Java-Prozedur eingeben / ausgeben, müssen Sie dem ausführenden Benutzer die entsprechenden Berechtigungen erteilen.
Das Erteilen der Ausführungsberechtigung ist die Prozedur GRANT_PERMISSION im Paket DBMS_JAVA. Als privilegierter Benutzer ausführen (SYS, DBA-Berechtigung).
CALL dbms_java.grant_permission( '<Berechtigungszielschema>', 'SYS:java.io.FilePermission', '<<ALL FILES>>', 'execute' );
Im obigen Fall werden alle Dateien als Ziel ausgewählt. Wenn also ein Sicherheitsproblem vorliegt, ist der Bereich auf cmd.exe beschränkt.
call dbms_java.grant_permission('<Autorisierungszielschema>', 'SYS:java.io.FilePermission','C:\WINDOWS\system32\cmd.exe','execute');
So überprüfen Sie Berechtigungen
select * from DBA_JAVA_POLICY;
So entfernen Sie Berechtigungen
begin
DBMS_JAVA.disable_permission(<SEQ>);
DBMS_JAVA.delete_permission(<SEQ>);
end;
Führen Sie den Befehl mit der Spalte KeyName der FUGA-Tabelle als Argument aus. Der Batch (test.bat) wird in FuncExec aufgerufen.
TRG_LOGOUTPUT
CREATE OR REPLACE TRIGGER "TEST"."TRG_LOGOUTPUT"
AFTER INSERT
ON FUGA
FOR EACH ROW
DECLARE
sResult VARCHAR2(200);
BEGIN
IF INSERTING THEN
SELECT FuncExec(:new.KeyName) INTO sResult FROM DUAL;
END IF;
END;
Ein Batch (test.bat) wird vom Trigger mit dem Schlüssel als Argument aufgerufen. Erhalten Sie diesen Schlüssel und geben Sie das Protokoll aus. Selbst wenn Sie zu diesem Zeitpunkt AUSWÄHLEN, können die Zieldaten nicht abgerufen werden, da sie noch nicht festgeschrieben wurden. Bereiten Sie daher eine weitere Charge (test2.bat) vor und legen Sie ein Kissen für die Ausgabe des Protokolls.
test.bat
cd /d %~dp0
start test2 %1
test2.bat
cd /d %~dp0
outputlog.exe %1
exit
Mit dieser Methode befinden Sie sich in einem festgeschriebenen Zustand und können die Zieldaten abrufen. Wenn es zurückgesetzt wird, wird kein Protokoll ausgegeben, da die Zieldaten nicht gefunden werden können.
Jetzt, da ich es mit gespeichertem Java machen kann, habe ich auch die DBMS_SCHEDULER-Methode ausprobiert.
Erteilen Sie Berechtigungen zum Ausführen von DBMS_SCHEDULER. Als privilegierter Benutzer ausführen (SYS, DBA-Berechtigung).
SQL>GRANT CREATE JOB TO <Benutzername>;
Die Autorisierung war erfolgreich.
SQL>GRANT CREATE REATE EXTERNAL JOB TO <Benutzername>;
Die Autorisierung war erfolgreich.
Führen Sie den Befehl mit der Spalte KeyName der FUGA-Tabelle als Argument aus. Geben Sie zu diesem Zeitpunkt "autonomous_transaction" der autonomen Transaktion an.
TRG_LOGOUTPUT
CREATE OR REPLACE TRIGGER TRG_LOGOUTPUT
BEFORE INSERT OR UPDATE
ON FUGA
FOR EACH ROW
DECLARE
pragma autonomous_transaction;
BEGIN
IF INSERTING THEN
DBMS_SCHEDULER.CREATE_JOB (
JOB_NAME => 'job_test',
JOB_TYPE => 'EXECUTABLE',
JOB_ACTION => 'C:\WINDOWS\system32\cmd.exe',
number_of_arguments => 3,
AUTO_DROP => TRUE);
DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE('job_test',1, '/c');
DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE('job_test',2, 'C:\foo\test.bat');
DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE('job_test',3, :new.KeyName);
DBMS_SCHEDULER.ENABLE('job_test');
END IF;
END;
Beim Aufrufen von DBMS_SCHEDULER.CREATE_JOB wird ein implizites Commit ausgegeben. Normalerweise schlägt es fehl, weil es nicht innerhalb des Triggers festgeschrieben werden kann, aber es kann vermieden werden, indem die autonome Transaktion "autonomous_transaction" verwendet wird.
Der Teil, der durch "Erstellen eines dbms_scheduler.create_job mit Argumenten --stackoverflow" gelöst wurde. ist.
Bei der Eingabe von "enabled => TRUE" wie unten gezeigt wurde die Fehlermeldung "ORA-27457: Argument 1 (Job" TEST.JOB_TEST ") hat keinen Wert" angezeigt.
number_of_arguments => 3,
enabled => TRUE,
AUTO_DROP => TRUE);
Dies ist ein Fehler, da der Job sofort beim Erstellen wirksam wird, die Argumente zu diesem Zeitpunkt jedoch noch nicht festgelegt wurden. "Enabled => TRUE" ist in Ordnung, wenn kein Argument vorhanden ist. Wenn jedoch ein Argument vorhanden ist, muss es nach dem Festlegen des Arguments aktiviert werden.
Ein Batch (test.bat) wird vom Trigger mit dem Schlüssel als Argument aufgerufen. Erhalten Sie diesen Schlüssel und geben Sie das Protokoll aus. Im Gegensatz zu gespeichertem Java wird es bereits bei der Stapelausführung festgeschrieben, sodass kein Polster erforderlich ist. Wenn es zurückgesetzt wird, wird kein Protokoll ausgegeben, da die Zieldaten nicht gefunden werden können.
test.bat
cd /d %~dp0
outputlog.exe %1
Am Ende verschwand die Änderung zur Ausgabe des Protokolls und es wurde eine andere Methode, aber es war eine gute Studie. Ich dachte, ich könnte einen Weg finden, indem ich leicht suche, aber es ist unerwartet. Es fühlt sich an, als könnte ich es endlich an verschiedenen Orten herausfinden und kombinieren.