La classe CallableStatement en Java est utilisée pour appeler une procédure stockée à partir d’un programme Java. Les procédures stockées sont un ensemble d’instructions que nous compilons dans la base de données pour effectuer une tâche particulière. Les procédures stockées sont bénéfiques lorsque nous travaillons avec plusieurs tables dans des scénarios complexes et plutôt que d’envoyer plusieurs requêtes à la base de données, nous pouvons envoyer les données nécessaires à la procédure stockée et faire exécuter la logique sur le serveur de base de données lui-même.
CallableStatement
L’API JDBC fournit un support pour exécuter des procédures stockées via l’interface
CallableStatement
. Les procédures stockées doivent être écrites dans une syntaxe spécifique à la base de données et pour mon tutoriel, j’utiliserai la base de données Oracle. Nous examinerons les fonctionnalités standard de CallableStatement avec des paramètres IN et OUT. Ensuite, nous examinerons des exemples spécifiques à Oracle de STRUCT et de Curseur. Créons d’abord une table pour nos programmes d’exemple CallableStatement avec la requête SQL suivante. create_employee.sql
-- Pour la base de données Oracle
CREATE TABLE EMPLOYEE
(
"EMPID" NUMBER NOT NULL ENABLE,
"NAME" VARCHAR2(10 BYTE) DEFAULT NULL,
"ROLE" VARCHAR2(10 BYTE) DEFAULT NULL,
"CITY" VARCHAR2(10 BYTE) DEFAULT NULL,
"COUNTRY" VARCHAR2(10 BYTE) DEFAULT NULL,
PRIMARY KEY ("EMPID")
);
Créons d’abord une classe utilitaire pour obtenir l’objet de connexion à la base de données Oracle. Assurez-vous que le jar Oracle OJDBC est dans le chemin de construction du projet. DBConnection.java
package com.journaldev.jdbc.storedproc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBConnection {
private static final String DB_DRIVER_CLASS = "oracle.jdbc.driver.OracleDriver";
private static final String DB_URL = "jdbc:oracle:thin:@localhost:1521:orcl";
private static final String DB_USERNAME = "HR";
private static final String DB_PASSWORD = "oracle";
public static Connection getConnection() {
Connection con = null;
try {
// chargez la classe Driver
Class.forName(DB_DRIVER_CLASS);
// créez maintenant la connexion
con = DriverManager.getConnection(DB_URL,DB_USERNAME,DB_PASSWORD);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return con;
}
}
Exemple de CallableStatement
Écrivons maintenant une procédure stockée simple pour insérer des données dans la table Employee. insertEmployee.sql
CREATE OR REPLACE PROCEDURE insertEmployee
(in_id IN EMPLOYEE.EMPID%TYPE,
in_name IN EMPLOYEE.NAME%TYPE,
in_role IN EMPLOYEE.ROLE%TYPE,
in_city IN EMPLOYEE.CITY%TYPE,
in_country IN EMPLOYEE.COUNTRY%TYPE,
out_result OUT VARCHAR2)
AS
BEGIN
INSERT INTO EMPLOYEE (EMPID, NAME, ROLE, CITY, COUNTRY)
values (in_id,in_name,in_role,in_city,in_country);
commit;
out_result := 'TRUE';
EXCEPTION
WHEN OTHERS THEN
out_result := 'FALSE';
ROLLBACK;
END;
Comme vous pouvez le voir, la procédure insertEmployee attend des entrées de l’appelant qui seront insérées dans la table Employee. Si l’instruction d’insertion fonctionne correctement, elle renvoie TRUE et en cas d’exception, elle renvoie FALSE. Voyons comment nous pouvons utiliser CallableStatement
pour exécuter la procédure stockée insertEmployee
pour insérer des données d’employé. JDBCStoredProcedureWrite.java
package com.journaldev.jdbc.storedproc;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Scanner;
public class JDBCStoredProcedureWrite {
public static void main(String[] args) {
Connection con = null;
CallableStatement stmt = null;
//Lire les entrées utilisateur
Scanner input = new Scanner(System.in);
System.out.println("Enter Employee ID (int):");
int id = Integer.parseInt(input.nextLine());
System.out.println("Enter Employee Name:");
String name = input.nextLine();
System.out.println("Enter Employee Role:");
String role = input.nextLine();
System.out.println("Enter Employee City:");
String city = input.nextLine();
System.out.println("Enter Employee Country:");
String country = input.nextLine();
try{
con = DBConnection.getConnection();
stmt = con.prepareCall("{call insertEmployee(?,?,?,?,?,?)}");
stmt.setInt(1, id);
stmt.setString(2, name);
stmt.setString(3, role);
stmt.setString(4, city);
stmt.setString(5, country);
//enregistrer le paramètre OUT avant d'appeler la procédure stockée
stmt.registerOutParameter(6, java.sql.Types.VARCHAR);
stmt.executeUpdate();
//lire le paramètre OUT maintenant
String result = stmt.getString(6);
System.out.println("Employee Record Save Success::"+result);
}catch(Exception e){
e.printStackTrace();
}finally{
try {
stmt.close();
con.close();
input.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
Nous lisons l’entrée utilisateur pour la stocker dans la table Employee. La seule différence avec PreparedStatement est la création de CallableStatement avec « {call insertEmployee(?,?,?,?,?,?)}
» et le paramétrage du paramètre OUT avec la méthode CallableStatement registerOutParameter()
. Nous devons enregistrer le paramètre OUT avant d’exécuter la procédure stockée. Une fois la procédure stockée exécutée, nous pouvons utiliser la méthode CallableStatement getXXX()
pour obtenir les données de l’objet OUT. Notez que lors de l’enregistrement du paramètre OUT, nous devons spécifier le type de paramètre OUT via java.sql.Types
. Le code est générique, donc si nous avons la même procédure stockée dans une autre base de données relationnelle comme MySQL, nous pouvons les exécuter avec ce programme également. Voici la sortie lorsque nous exécutons le programme d’exemple de CallableStatement plusieurs fois.
Enter Employee ID (int):
1
Enter Employee Name:
Pankaj
Enter Employee Role:
Developer
Enter Employee City:
Bangalore
Enter Employee Country:
India
Employee Record Save Success::TRUE
-----
Enter Employee ID (int):
2
Enter Employee Name:
Pankaj Kumar
Enter Employee Role:
CEO
Enter Employee City:
San Jose
Enter Employee Country:
USA
Employee Record Save Success::FALSE
Remarquez que la deuxième exécution a échoué car le nom passé est plus grand que la taille de la colonne. Nous consommons l’exception dans la procédure stockée et renvoyons false dans ce cas.
Exemple de CallableStatement – Paramètres OUT de procédure stockée
Maintenant, écrivons une procédure stockée pour obtenir les données de l’employé par ID. L’utilisateur entrera l’ID de l’employé et le programme affichera les informations de l’employé. getEmployee.sql
create or replace
PROCEDURE getEmployee
(in_id IN EMPLOYEE.EMPID%TYPE,
out_name OUT EMPLOYEE.NAME%TYPE,
out_role OUT EMPLOYEE.ROLE%TYPE,
out_city OUT EMPLOYEE.CITY%TYPE,
out_country OUT EMPLOYEE.COUNTRY%TYPE
)
AS
BEGIN
SELECT NAME, ROLE, CITY, COUNTRY
INTO out_name, out_role, out_city, out_country
FROM EMPLOYEE
WHERE EMPID = in_id;
END;
Le programme d’exemple Java CallableStatement utilisant la procédure stockée getEmployee pour lire les données de l’employé est; JDBCStoredProcedureRead.java
package com.journaldev.jdbc.storedproc;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Scanner;
public class JDBCStoredProcedureRead {
public static void main(String[] args) {
Connection con = null;
CallableStatement stmt = null;
// Lire les entrées de l'utilisateur
Scanner input = new Scanner(System.in);
System.out.println("Enter Employee ID (int):");
int id = Integer.parseInt(input.nextLine());
try{
con = DBConnection.getConnection();
stmt = con.prepareCall("{call getEmployee(?,?,?,?,?)}");
stmt.setInt(1, id);
// Enregistrer le paramètre OUT avant d'appeler la procédure stockée
stmt.registerOutParameter(2, java.sql.Types.VARCHAR);
stmt.registerOutParameter(3, java.sql.Types.VARCHAR);
stmt.registerOutParameter(4, java.sql.Types.VARCHAR);
stmt.registerOutParameter(5, java.sql.Types.VARCHAR);
stmt.execute();
// Lire maintenant le paramètre OUT
String name = stmt.getString(2);
String role = stmt.getString(3);
String city = stmt.getString(4);
String country = stmt.getString(5);
if(name !=null){
System.out.println("Employee Name="+name+",Role="+role+",City="+city+",Country="+country);
}else{
System.out.println("Employee Not Found with ID"+id);
}
}catch(Exception e){
e.printStackTrace();
}finally{
try {
stmt.close();
con.close();
input.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
Encore une fois, le programme est générique et fonctionne pour n’importe quelle base de données ayant la même procédure stockée. Voyons quel est le résultat lorsque nous exécutons le programme d’exemple CallableStatement ci-dessus.
Enter Employee ID (int):
1
Employee Name=Pankaj,Role=Developer,City=Bangalore,Country=India
Exemple de CallableStatement – Curseur Oracle de procédure stockée
Étant donné que nous lisons les informations sur l’employé par ID, nous obtenons un seul résultat et les paramètres OUT fonctionnent bien pour lire les données. Mais si nous recherchons par rôle ou par pays, nous pourrions obtenir plusieurs lignes et dans ce cas, nous pouvons utiliser le CURSEUR Oracle pour les lire comme un ensemble de résultats. getEmployeeByRole.sql
create or replace
PROCEDURE getEmployeeByRole
(in_role IN EMPLOYEE.ROLE%TYPE,
out_cursor_emps OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN out_cursor_emps FOR
SELECT EMPID, NAME, CITY, COUNTRY
FROM EMPLOYEE
WHERE ROLE = in_role;
END;
JDBCStoredProcedureCursor.java
package com.journaldev.jdbc.storedproc;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;
import oracle.jdbc.OracleTypes;
public class JDBCStoredProcedureCursor {
public static void main(String[] args) {
Connection con = null;
CallableStatement stmt = null;
ResultSet rs = null;
// Lire les entrées de l'utilisateur
Scanner input = new Scanner(System.in);
System.out.println("Enter Employee Role:");
String role = input.nextLine();
try{
con = DBConnection.getConnection();
stmt = con.prepareCall("{call getEmployeeByRole(?,?)}");
stmt.setString(1, role);
// Enregistrer le paramètre OUT avant d'appeler la procédure stockée
stmt.registerOutParameter(2, OracleTypes.CURSOR);
stmt.execute();
// Lire maintenant le paramètre OUT
rs = (ResultSet) stmt.getObject(2);
while(rs.next()){
System.out.println("Employee ID="+rs.getInt("empId")+",Name="+rs.getString("name")+
",Role="+role+",City="+rs.getString("city")+
",Country="+rs.getString("country"));
}
}catch(Exception e){
e.printStackTrace();
}finally{
try {
rs.close();
stmt.close();
con.close();
input.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
Ce programme utilise des classes spécifiques Oracle OJDBC et ne fonctionnera pas avec d’autres bases de données. Nous définissons le type de paramètre OUT comme OracleTypes.CURSOR
et le castons ensuite en objet ResultSet
. L’autre partie du code est une programmation JDBC simple. Lorsque nous exécutons le programme d’exemple de CallableStatement ci-dessus, nous obtenons la sortie suivante.
Enter Employee Role:
Developer
Employee ID=5,Name=Kumar,Role=Developer,City=San Jose,Country=USA
Employee ID=1,Name=Pankaj,Role=Developer,City=Bangalore,Country=India
Votre sortie peut varier en fonction des données dans votre table Employee.
Exemple de CallableStatement – Objet et STRUCT Oracle DB
Si vous regardez les procédures stockées insertEmployee
et getEmployee
, j’ai tous les paramètres de la table Employee dans la procédure. Lorsque le nombre de colonnes augmente, cela peut entraîner de la confusion et rendre le code plus sujet aux erreurs. La base de données Oracle propose une option pour créer un objet de base de données et nous pouvons utiliser Oracle STRUCT pour travailler avec eux. Définissons d’abord l’objet de base de données Oracle pour les colonnes de la table Employee. EMPLOYEE_OBJ.sql
create or replace TYPE EMPLOYEE_OBJ AS OBJECT
(
EMPID NUMBER,
NAME VARCHAR2(10),
ROLE VARCHAR2(10),
CITY VARCHAR2(10),
COUNTRY VARCHAR2(10)
);
Passons maintenant à la réécriture de la procédure stockée insertEmployee
en utilisant EMPLOYEE_OBJ. insertEmployeeObject.sql
CREATE OR REPLACE PROCEDURE insertEmployeeObject
(IN_EMPLOYEE_OBJ IN EMPLOYEE_OBJ,
out_result OUT VARCHAR2)
AS
BEGIN
INSERT INTO EMPLOYEE (EMPID, NAME, ROLE, CITY, COUNTRY) values
(IN_EMPLOYEE_OBJ.EMPID, IN_EMPLOYEE_OBJ.NAME, IN_EMPLOYEE_OBJ.ROLE, IN_EMPLOYEE_OBJ.CITY, IN_EMPLOYEE_OBJ.COUNTRY);
commit;
out_result := 'TRUE';
EXCEPTION
WHEN OTHERS THEN
out_result := 'FALSE';
ROLLBACK;
END;
Voyons comment nous pouvons appeler la procédure stockée insertEmployeeObject
dans le programme Java. JDBCStoredProcedureOracleStruct.java
package com.journaldev.jdbc.storedproc;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Scanner;
import oracle.jdbc.OracleCallableStatement;
import oracle.sql.STRUCT;
import oracle.sql.StructDescriptor;
public class JDBCStoredProcedureOracleStruct {
public static void main(String[] args) {
Connection con = null;
OracleCallableStatement stmt = null;
//Créer un tableau d'objets pour l'appel de la procédure stockée
Object[] empObjArray = new Object[5];
//Lire les entrées utilisateur
Scanner input = new Scanner(System.in);
System.out.println("Enter Employee ID (int):");
empObjArray[0] = Integer.parseInt(input.nextLine());
System.out.println("Enter Employee Name:");
empObjArray[1] = input.nextLine();
System.out.println("Enter Employee Role:");
empObjArray[2] = input.nextLine();
System.out.println("Enter Employee City:");
empObjArray[3] = input.nextLine();
System.out.println("Enter Employee Country:");
empObjArray[4] = input.nextLine();
try{
con = DBConnection.getConnection();
StructDescriptor empStructDesc = StructDescriptor.createDescriptor("EMPLOYEE_OBJ", con);
STRUCT empStruct = new STRUCT(empStructDesc, con, empObjArray);
stmt = (OracleCallableStatement) con.prepareCall("{call insertEmployeeObject(?,?)}");
stmt.setSTRUCT(1, empStruct);
//Enregistrer le paramètre OUT avant d'appeler la procédure stockée
stmt.registerOutParameter(2, java.sql.Types.VARCHAR);
stmt.executeUpdate();
//Lire le paramètre OUT maintenant
String result = stmt.getString(2);
System.out.println("Employee Record Save Success::"+result);
}catch(Exception e){
e.printStackTrace();
}finally{
try {
stmt.close();
con.close();
input.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
Tout d’abord, nous créons un tableau d’objets de la même longueur que l’objet de base de données EMPLOYEE_OBJ. Ensuite, nous définissons les valeurs en fonction des variables d’objet EMPLOYEE_OBJ. C’est très important, sinon les données seront insérées dans de mauvaises colonnes. Ensuite, nous créons un objet oracle.sql.STRUCT
à l’aide de oracle.sql.StructDescriptor
et de notre tableau d’objets. Une fois que l’objet STRUCT est créé, nous le définissons comme paramètre IN pour la procédure stockée, enregistrons le paramètre OUT et l’exécutons. Ce code est étroitement lié à l’API OJDBC et ne fonctionnera pas pour d’autres bases de données. Voici la sortie lorsque nous exécutons ce programme.
Enter Employee ID (int):
5
Enter Employee Name:
Kumar
Enter Employee Role:
Developer
Enter Employee City:
San Jose
Enter Employee Country:
USA
Employee Record Save Success::TRUE
Nous pouvons utiliser l’objet de base de données en tant que paramètre OUT également et le lire pour obtenir les valeurs de la base de données. C’est tout pour l’exemple de CallableStatement en Java pour exécuter des procédures stockées. J’espère que vous avez appris quelque chose.
Source:
https://www.digitalocean.com/community/tutorials/callablestatement-in-java-example