Come invocare una stored procedure con Hibernate e Spring

Programmazione - Java Visite: 10177
document_2 Come invocare una stored procedure con Hibernate e Spring
Vediamo come si può invocare una stored procedure in Java e con il framework Spring. 
Prima di vedere i vari metodi vi elenco un problema da me ancora non risolto.
A quanto pare è un problema relativo ad hibernate e alle stored procedure.
Ad es. una stored procedure Oracle può essere fatta così:

function funzioneTest(param1 IN number,
param2 OUT numer,
param3 OUT number)
RETURN param4 number;

Ovvero questa stored procedure riceve in input 3 parametri ma solo il primo, param1, è quello di input vero e proprio, param2 e param3 sono valori
che vengono passati in input ma usati ome parametri di output. In più param4 è il classico parametro restituito.
A quanto pare i parametri di output dichiarati come OUT non vengono gestiti da hibernate.

1) PRIMO METODO

Nel codice si scrive:
Session session = (Session) em.getDelegate();
org.hibernate.Query namedQuery = session.getNamedQuery("nomeStoredProcedure");
//namedQuery.setBigDecimal(0, new BigDecimal(id));
List list = namedQuery.list();
session.close();

si utilizzano le named query. Se ci sono dei parametri da passare si usa l'istruzione commentata.
Dove si dichiara la namedQuery?

La stored procedure sarà dichiarata in un file XML chiamato nomeStoredProcedure.hbm.xml e fatto così:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>  
  <sql-query name="nomeStoredProcedure" callable="true" >
   <return-scalar column="value" type="big_decimal"  />
   <return-scalar column="value2" type="big_decimal"  />
    { call nometablespace.nomepackage.nomestoredprocedure(?) } 
  </sql-query>  
</hibernate-mapping>

Ovvero nel file XML c'è specificata la query e i parametri da usare per chiamare la nostra stored procedure.
Nel file hibernate.cfg.xml dovete ora indicare che questo file esiste:

<!-- Mapping files -->
<mapping resource="it/miopackage/module/nomestoredprocedure.hbm.xml"/>

Non so per quale motivo ma in alcuni casi questo metodo mi generva degli errori che non mi permettevano l'invocazione della stored procedure!!!

2) SECONDO METODO

La stored procedure può essere invocata come una normale query così:

String sqlQuery = "select nometablespace.nomepackage.nomestoredprocedure(" + id + ") from dual";
Query q = em.createNativeQuery(sqlQuery);
results = q.getResultList();
if(results==null || results.size()==0)
return o;
else
{
o = (BigDecimal)results.get(0);
}
return o;
In questo caso però la stored procedure deve essere fatta così:
deve dichiarare in testa PRAGMA AUTONOMOUS_TRANSACTION;
ed utilizzare al suo interno la commit e la rollback.
Ovvero la stored procedure, al suo interno, deve gestire le transazioni altrimenti l'esecuzione della query genera un errore del tipo
ORA-14551: impossibile eseguire un'operazione DML all'interno di una query 
Questo perché il sistema capisce che si sta eseguendo una select e che al suo interno si fa una INSERT e questo non è permesso.

3) TERZO METODO

Ad oggi per me è il migliore.
Connection conn = null;
CallableStatement cs = null;
BigDecimal retVal = null;

conn = dataSource.getConnection();
cs = conn.prepareCall("{ ? = call nometablespace.nomepackage.nomestoredprocedure(?)}");
cs.registerOutParameter(1, Types.BIGINT);
cs.setLong(2, id);
cs.execute();
retVal = cs.getBigDecimal(1);
return retVal;