Il y avait une demande de modification des journaux de sortie des tables utilisées par les applications développées en interne et les tables associées. Reportez-vous au journal pour qu'une autre application externe produise des informations. Le moment de sortie du journal était lorsque l'application a enregistré les données dans la table. Dans ce cas, j'ai senti qu'il serait possible d'exécuter un lot en utilisant un déclencheur de base de données sans modifier l'application, j'ai donc décidé d'enquêter. Je ne veux pas modifier l'application autant que possible.
Il existe deux façons d'appeler un lot Windows.
Si vous souhaitez simplement générer le fichier journal, vous pouvez utiliser le package UTL_FILE ou le package java.io sur Java stocké, mais compte tenu de la polyvalence de l'enregistrement sur une destination de lecteur réseau ou autre, il est préférable de le traiter à la destination qui a appelé le lot Windows. Quelque chose est pratique. Référence: Considérez comment générer des journaux à partir de PL / SQL
Oracle a implémenté une machine virtuelle Java qui permet aux programmes Java de s'exécuter sur la base de données. Je n'ai utilisé que PL / SQL auparavant, c'est donc une bonne occasion d'apprendre Java stocké.
J'ai fait référence au site de "Java utilisé en PL / SQL".
Une fois que vous avez créé un Java stocké, vous devrez également créer un wrapper pour l'appeler. Le wrapper ne doit être créé qu'une seule fois s'il n'y a pas de changement dans l'argument ou la valeur de retour, et le résultat sera reflété même si le contenu de Java stocké est réécrit plus tard.
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'
;
/
Il peut être utilisé de la même manière que l'appel d'une fonction utilisateur PL / SQL. Intéressant.
SELECT kasanf(2,3) FROM DUAL;
KASANF(2,3)
-----------
5
Exécutez un lot Windows (test.bat) en passant un argument à l'aide de la méthode Runtime.getRuntime (). Exec qui exécute une commande à partir de Java.
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'
;
/
Lors de l'exécution de commandes ou de l'entrée / sortie de fichiers dans une procédure stockée Java, il est nécessaire d'accorder les autorisations appropriées à l'utilisateur exécutant.
L'octroi de l'autorisation d'exécution est la procédure GRANT_PERMISSION du package DBMS_JAVA. Exécuter en tant qu'utilisateur privilégié (SYS, autorité DBA).
CALL dbms_java.grant_permission( '<Schéma de destination des privilèges>', 'SYS:java.io.FilePermission', '<<ALL FILES>>', 'execute' );
Dans le cas ci-dessus, tous les fichiers sont ciblés, donc en cas de problème de sécurité, la plage est limitée à cmd.exe.
call dbms_java.grant_permission('<Schéma de destination de l'autorisation>', 'SYS:java.io.FilePermission','C:\WINDOWS\system32\cmd.exe','execute');
Comment vérifier les autorisations
select * from DBA_JAVA_POLICY;
Comment supprimer les autorisations
begin
DBMS_JAVA.disable_permission(<SEQ>);
DBMS_JAVA.delete_permission(<SEQ>);
end;
Exécutez la commande avec la colonne KeyName de la table FUGA comme argument. Le batch (test.bat) est appelé dans FuncExec.
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;
Un batch (test.bat) est appelé à partir du déclencheur avec la clé comme argument. Recevez cette clé et sortez le journal. Cependant, même si vous SELECT à ce stade, les données cibles ne peuvent pas être obtenues car elles n'ont pas encore été validées. Par conséquent, préparez un autre lot (test2.bat) et placez un coussin pour sortir le journal.
test.bat
cd /d %~dp0
start test2 %1
test2.bat
cd /d %~dp0
outputlog.exe %1
exit
Par cette méthode, vous serez dans un état validé et vous pourrez récupérer les données cibles. En outre, s'il est annulé, aucun journal ne sera généré car les données cibles sont introuvables.
Maintenant que je peux le faire avec Java stocké, j'ai également essayé la méthode DBMS_SCHEDULER.
Accordez les autorisations pour exécuter DBMS_SCHEDULER. Exécuter en tant qu'utilisateur privilégié (SYS, autorité DBA).
SQL>GRANT CREATE JOB TO <nom d'utilisateur>;
L'autorisation a réussi.
SQL>GRANT CREATE REATE EXTERNAL JOB TO <nom d'utilisateur>;
L'autorisation a réussi.
Exécutez la commande avec la colonne KeyName de la table FUGA comme argument. À ce moment, spécifiez "transaction_autonome" de la transaction autonome.
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;
L'appel de DBMS_SCHEDULER.CREATE_JOB émet une validation implicite. Normalement, elle échoue car elle ne peut pas être validée à l'intérieur du déclencheur, mais elle peut être évitée en utilisant la transaction autonome "transaction_autonome".
La partie qui a été résolue par "Création d'un dbms_scheduler.create_job avec des arguments --stackoverflow" est.
Lorsque j'ai entré "enabled => TRUE" comme indiqué ci-dessous, j'ai eu une erreur "ORA-27457: Argument 1 (job" TEST.JOB_TEST ") n'a pas de valeur".
number_of_arguments => 3,
enabled => TRUE,
AUTO_DROP => TRUE);
Il s'agit d'une erreur car le travail prend effet immédiatement lors de sa création, mais les arguments n'ont pas encore été définis à ce stade. "Enabled => TRUE" convient s'il n'y a pas d'argument, mais s'il y a un argument, il doit être activé après avoir défini l'argument.
Un batch (test.bat) est appelé à partir du déclencheur avec la clé comme argument. Recevez cette clé et sortez le journal. Contrairement à Java stocké, il est déjà validé lors de l'exécution par lots, il n'est donc pas nécessaire de mettre un coussin. S'il est annulé, aucun journal ne sera généré car les données cibles sont introuvables.
test.bat
cd /d %~dp0
outputlog.exe %1
En fin de compte, la modification pour sortir le journal a disparu et c'est devenu une autre méthode, mais c'était une bonne étude. Je pensais pouvoir trouver un moyen en cherchant facilement, mais c'est inattendu. J'ai l'impression que je peux enfin trouver de divers endroits et les combiner.