web-dev-qa-db-fra.com

Comment appeler une procédure stockée avec Hibernate et JPA?

Comment appeler une procédure stockée à l'aide d'Hibernate ou de JPA?

16
kandarp

Vous pouvez faire ce qui suit

 Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
PreparedStatement st = session.connection().prepareStatement("{call procedureName(?, ?)}");
                st.setString(1, formatter.format(parameter1));
                st.setString(2, formatter.format(parameter2));
                st.execute();
tx.commit();

S'il vous plaît ajouter la gestion des exceptions, le cas échéant. 

2
Deepak Singh Rawat

Considérant la procédure stockée suivante qui renvoie simplement une valeur de retour de base:

CREATE OR REPLACE PROCEDURE count_comments (  
   postId IN NUMBER,  
   commentCount OUT NUMBER )  
AS 
BEGIN 
    SELECT COUNT(*) INTO commentCount  
    FROM post_comment  
    WHERE post_id = postId; 
END;

Vous pouvez appeler celui-ci avec JPA standard:

StoredProcedureQuery query = entityManager
    .createStoredProcedureQuery("count_comments")
    .registerStoredProcedureParameter(1, Long.class, 
        ParameterMode.IN)
    .registerStoredProcedureParameter(2, Long.class, 
        ParameterMode.OUT)
    .setParameter(1, 1L);

query.execute();

Long commentCount = (Long) query.getOutputParameterValue(2);

Si la procédure stockée retourne SYS_REFCURSOR:

CREATE OR REPLACE PROCEDURE post_comments ( 
   postId IN NUMBER, 
   postComments OUT SYS_REFCURSOR ) 
AS 
BEGIN
    OPEN postComments FOR
    SELECT *
    FROM post_comment 
    WHERE post_id = postId; 
END;

Vous pouvez l'appeler comme ça:

StoredProcedureQuery query = entityManager
    .createStoredProcedureQuery("post_comments")
    .registerStoredProcedureParameter(1, Long.class, 
         ParameterMode.IN)
    .registerStoredProcedureParameter(2, Class.class, 
         ParameterMode.REF_CURSOR)
    .setParameter(1, 1L);

query.execute();

List<Object[]> postComments = query.getResultList();

Si vous souhaitez appeler une fonction de base de données Oracle:

CREATE OR REPLACE FUNCTION fn_count_comments ( 
    postId IN NUMBER ) 
    RETURN NUMBER 
IS
    commentCount NUMBER; 
BEGIN
    SELECT COUNT(*) INTO commentCount 
    FROM post_comment 
    WHERE post_id = postId; 
    RETURN( commentCount ); 
END;

Vous ne pouvez pas utiliser StoredProcedureQuery car il ne fonctionne pas avec Hibernate 5, vous pouvez donc l'appeler ainsi:

BigDecimal commentCount = (BigDecimal) entityManager
    .createNativeQuery(
        "SELECT fn_count_comments(:postId) FROM DUAL"
    )
    .setParameter("postId", 1L)
    .getSingleResult();

ou avec JDBC simple:

Session session = entityManager.unwrap( Session.class ); 

Integer commentCount = session.doReturningWork( connection -> {
    try (CallableStatement function = connection.prepareCall(
            "{ ? = call fn_count_comments(?) }" )) {
        function.registerOutParameter( 1, Types.INTEGER );
        function.setInt( 2, 1 );
        function.execute();
        return function.getInt( 1 );
    }
} );

Pour plus de détails, consultez les articles suivants:

12
Vlad Mihalcea

Pour exécuter une procédure à distance, utilisez cette construction:

Cartographie

<sql-query name="RP">   
    {call some_rp(:param1, :param2)}
</sql-query>

Code Java

session.getNamedQuery("RP").setInteger("param1", 1).setInteger("param2", 2).executeUpdate();
2
Mikhail.Mamaev
One way to call the stored procedure from hibernate 

Declare your store procedure inside the @NamedNativeQueries annotation

//Stock.Java

@NamedNativeQueries({
    @NamedNativeQuery(
    name = "callStockStoreProcedure",
    query = "CALL GetStocks(:stockCode)",
    resultClass = Stock.class
    )
})
@Entity
@Table(name = "stock")
public class Stock implements Java.io.Serializable {

Call it with getNamedQuery().

Query query = session.getNamedQuery("callStockStoreProcedure")
    .setParameter("stockCode", "7277");
List result = query.list();
for(int i=0; i<result.size(); i++){
    Stock stock = (Stock)result.get(i);
    System.out.println(stock.getStockCode());
}

This works
1
SandeepJain

Vous auriez dû vous rendre sur le site officiel de documentation d'hibernation. Quoi qu'il en soit voici le lien qui vous emmène directement à la section procédure stockée

0
Aravind R. Yarram

une approche peut être avec getNamedQuery ().

Query query = session.getNamedQuery("callStockStoreProcedure")
    .setParameter("stockCode", "7277");
List result = query.list();
for(int i=0; i<result.size(); i++){
    Stock stock = (Stock)result.get(i);
    System.out.println(stock.getStockCode());
}

vous devez mapper ou utiliser des annotations

il y en a d'autres: source

0
demian

Voici la solution complète pour appeler une procédure stockée avec les paramètres Just IN ---

1) Créez la procédure stockée pour agir sur une table ou un ensemble de tables:

CREATE OR REPLACE procedure insertHouseHello (
house_date in timestamp,
house_name in varchar2,
house_number in number,
house_value in float) 
is
begin
 insert into House("HOUSE_DATE","HOUSE_NAME","HOUSE_NUMBER","HOUSE_VALUE")
 values ( house_date, house_name,house_number,house_value);
 commit;
 end;

2) Exécutez la procédure stockée à partir de l'invite SQL pour vérifier l'entrée. Lorsque vous appelez la procédure à partir de Java/Hibernate également, vous devriez voir le résultat similaire:

exec insertHouseHello(sysdate,'one',123,104); 

3) Dans le code Java:

log.info("Now trying to call the Stored Procedure*****************");
Query exQuery = session.createSQLQuery("CALL " +
        "insertHouseHello(:timestmp,:hname,:hno,:hvalue)");
exQuery.setParameter("timestmp", 
        new Java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
exQuery.setParameter("hname", 34);
exQuery.setParameter("hno", 212);
exQuery.setParameter("hvalue", 12);
int exRows = exQuery.executeUpdate();
log.info("Executed Rows from Stored Procedure****************"+exRows);

4) Maintenant, vérifiez le résultat dans le tableau, cela devrait être mis à jour en conséquence:

0
kanaparthikiran

Hibernate fournit un support pour les requêtes via des procédures et des fonctions stockées. Disons par exemple si nous avons la procédure stockée suivante,

CREATE OR REPLACE FUNCTION selectAllEmployments
RETURN SYS_REFCURSOR
AS
    st_cursor SYS_REFCURSOR;
BEGIN
    OPEN st_cursor FOR
 SELECT EMPLOYEE, EMPLOYER,
 STARTDATE, ENDDATE,
 REGIONCODE, EID, VALUE, CURRENCY
 FROM EMPLOYMENT;
      RETURN  st_cursor;
 END;

Ce qui retourne la liste de tous les employés. La procédure/fonction stockée doit renvoyer un jeu de résultats en tant que premier paramètre de sortie pour pouvoir fonctionner avec Hibernate. 

Pour utiliser la requête ci-dessus dans Hibernate, vous devez la mapper via une requête nommée.

<sql-query name="selectAllEmployees_SP" callable="true">
    <return alias="emp" class="Employment">
        <return-property name="employee" column="EMPLOYEE"/>
        <return-property name="employer" column="EMPLOYER"/>
        <return-property name="startDate" column="STARTDATE"/>
        <return-property name="endDate" column="ENDDATE"/>
        <return-property name="regionCode" column="REGIONCODE"/>
        <return-property name="id" column="EID"/>
        <return-property name="salary">
            <return-column name="VALUE"/>
            <return-column name="CURRENCY"/>
        </return-property>
    </return>
    { ? = call selectAllEmployments() }
</sql-query>

Règles/limitations d'utilisation des procédures stockées:

  • Les requêtes de procédure stockées ne peuvent pas être paginées avec setFirstResult ()/setMaxResults ().
  • Le format d'appel recommandé est le standard SQL92: { ? = call functionName(<parameters>) } ou { ? = call procedureName(<parameters>}. La syntaxe d'appel natif n'est pas prise en charge.

_ {For Oracle the following rules apply:

  • Une fonction doit renvoyer un jeu de résultats. 
  • Le premier paramètre d'une procédure doit être une sortie qui renvoie un ensemble de résultats. Pour ce faire, utilisez un type SYS_REFCURSOR dans Oracle 9 ou 10. Sous Oracle, vous devez définir un type REF CURSOR. Voir la documentation Oracle pour plus d'informations.

_ {For Sybase or MS SQL server the following rules apply:

  • La procédure doit renvoyer un jeu de résultats. Notez que, puisque ces serveurs peuvent renvoyer plusieurs ensembles de résultats et mettre à jour des nombres, Hibernate itérera les résultats et prendra le premier résultat correspondant à un ensemble de résultats comme valeur de retour. Tout le reste sera jeté.
  • Si vous pouvez activer SET NOCOUNT ON dans votre procédure, cela sera probablement plus efficace, mais ce n'est pas une obligation.

Référence de la source: D'après la documentation officielle d'Hibernate.

0
Lucky