Ich schreibe eine einfache Webanwendung, um eine gespeicherte Prozedur aufzurufen und Daten abzurufen. Dies ist eine sehr einfache Anwendung, die mit der Datenbank des Kunden interagiert. Wir übergeben die Personal-ID und die Firmen-ID, und die gespeicherte Prozedur gibt die Details zu den Mitarbeitern zurück.
Die Webanwendung kann keine Daten aktualisieren/löschen und verwendet SQL Server.
Ich setze meine Webanwendung in Jboss AS ein. Sollte ich JPA verwenden, um auf die gespeicherte Prozedur oder CallableStatement
zuzugreifen. Jeder Vorteil der Verwendung von JPA in diesem Fall.
Wie lautet die SQL-Anweisung, um diese gespeicherte Prozedur aufzurufen. Ich habe noch nie gespeicherte Prozeduren verwendet und kämpfe mit dieser Prozedur. Google war keine große Hilfe.
Hier ist die gespeicherte Prozedur:
CREATE procedure getEmployeeDetails (@employeeId int, @companyId int)
as
begin
select firstName,
lastName,
gender,
address
from employee et
where et.employeeId = @employeeId
and et.companyId = @companyId
end
Aktualisieren:
Für alle anderen, die Probleme haben, die gespeicherte Prozedur mitJPAaufzurufen.
Query query = em.createNativeQuery("{call getEmployeeDetails(?,?)}",
EmployeeDetails.class)
.setParameter(1, employeeId)
.setParameter(2, companyId);
List<EmployeeDetails> result = query.getResultList();
Dinge, die mir aufgefallen sind:
{call sp_name(?,?)}
anstelle von call sp_name(?,?)
getSingleResult
nicht, auch wenn Sie nur eine Zeile kennenresultSetMapping
-Namen oder eine ErgebnisklassendetailsJPA 2.1 unterstützt jetzt gespeicherte Prozeduren. Lesen Sie das Java-Dokument hier .
Beispiel:
StoredProcedureQuery storedProcedure = em.createStoredProcedureQuery("sales_tax");
// set parameters
storedProcedure.registerStoredProcedureParameter("subtotal", Double.class, ParameterMode.IN);
storedProcedure.registerStoredProcedureParameter("tax", Double.class, ParameterMode.OUT);
storedProcedure.setParameter("subtotal", 1f);
// execute SP
storedProcedure.execute();
// get result
Double tax = (Double)storedProcedure.getOutputParameterValue("tax");
Siehe detailliertes Beispiel hier .
Ich setze meine Webanwendung in Jboss AS ein. Sollte ich JPA verwenden, um auf die gespeicherte Prozedur oder das CallableStatement zuzugreifen. Jeder Vorteil der Verwendung von JPA in diesem Fall.
Es wird nicht wirklich von JPA unterstützt, aber es ist doable . Trotzdem würde ich nicht diesen Weg gehen:
Ich würde daher lieber die Verwendung von Spring für den JDBC-Datenzugriff oder einen Data-Mapper wie MyBatis oder - angesichts der Einfachheit Ihrer Anwendung - von JDBC und CallableStatement
in Betracht ziehen. Eigentlich wäre JDBC wahrscheinlich meine Wahl. Hier ist ein grundlegendes Kickoff-Beispiel:
CallableStatement cstmt = con.prepareCall("{call getEmployeeDetails(?, ?)}");
cstmt.setInt("employeeId", 123);
cstmt.setInt("companyId", 456);
ResultSet rs = cstmt.executeQuery();
Sie müssen die Parameter an die gespeicherte Prozedur übergeben.
Es sollte so funktionieren:
List result = em
.createNativeQuery("call getEmployeeDetails(:employeeId,:companyId)")
.setParameter("emplyoyeeId", 123L)
.setParameter("companyId", 456L)
.getResultList();
Update:
Oder vielleicht sollte es nicht.
Im Buch EJB3 in Aktion heißt es auf Seite 383, dass JPA keine gespeicherten Prozeduren unterstützt (Seite ist nur eine Vorschau, Sie erhalten nicht den vollständigen Text, das gesamte Buch ist als verfügbar ein Download an mehreren Stellen, einschließlich dieses , ich weiß nicht, ob dies legal ist).
Jedenfalls lautet der Text so:
Wenn Sie ein großer Fan von SQL sind, können Sie bereit, die Macht von .__ auszunutzen. gespeicherte Datenbankprozeduren . Leider unterstützt die JPA keine gespeicherte Prozeduren, und Sie müssen hängen von einer proprietären Funktion von .__ ab. Ihr Persistenzanbieter. Jedoch, Sie können einfache gespeicherte Funktionen verwenden (ohne out-Parameter) mit einem nativen SQL-Abfrage.
Obwohl diese Antwort darauf hinausläuft, ein Re-Cord-Set aus einer gespeicherten Prozedur zurückzugeben, poste ich hier, da ich mich lange Zeit erkundigt habe und dieser Thread mir geholfen hat.
Meine Anwendung verwendete Eclipselink-2.3.1, aber ich werde ein Upgrade auf Eclipselink-2.5.0 erzwingen, da JPA 2.1 für gespeicherte Prozeduren eine wesentlich bessere Unterstützung bietet.
Diese Methode erfordert den Import von EclipseLink-Klassen aus "org.Eclipse.persistence", daher ist sie spezifisch für die Eclipselink-Implementierung.
Ich habe es unter " http://www.yenlo.nl/de/calling-Oracle-stored-procedures-von-eclipselink-with-multiple-out-parameters " gefunden.
StoredProcedureCall storedProcedureCall = new StoredProcedureCall();
storedProcedureCall.setProcedureName("mypackage.myprocedure");
storedProcedureCall.addNamedArgument("i_input_1"); // Add input argument name.
storedProcedureCall.addNamedOutputArgument("o_output_1"); // Add output parameter name.
DataReadQuery query = new DataReadQuery();
query.setCall(storedProcedureCall);
query.addArgument("i_input_1"); // Add input argument names (again);
List<Object> argumentValues = new ArrayList<Object>();
argumentValues.add("valueOf_i_input_1"); // Add input argument values.
JpaEntityManager jpaEntityManager = (JpaEntityManager) getEntityManager();
Session session = jpaEntityManager.getActiveSession();
List<?> results = (List<?>) session.executeQuery(query, argumentValues);
DatabaseRecord record = (DatabaseRecord) results.get(0);
String result = String.valueOf(record.get("o_output_1")); // Get output parameter
Diese Methode ist implementierungsunabhängig (Eclipslink-Importe sind nicht erforderlich).
StoredProcedureQuery query = getEntityManager().createStoredProcedureQuery("mypackage.myprocedure");
query.registerStoredProcedureParameter("i_input_1", String.class, ParameterMode.IN);
query.registerStoredProcedureParameter("o_output_1", String.class, ParameterMode.OUT);
query.setParameter("i_input_1", "valueOf_i_input_1");
boolean queryResult = query.execute();
String result = String.valueOf(query.getOutputParameterValue("o_output_1"));
Wenn Sie EclipseLink verwenden, können Sie @NamedStoredProcedureQuery oder StoreProcedureCall verwenden, um gespeicherte Prozeduren auszuführen, einschließlich Prozeduren mit Ausgabeparametern oder Out-Cursor. Unterstützung für gespeicherte Funktionen und PLSQL-Datentypen ist ebenfalls verfügbar.
Siehe http://en.wikibooks.org/wiki/Java_Persistence/Advanced_Topics#Stored_Procedures
Für mich funktionierten nur folgende mit Oracle 11g und Glassfish 2.1 (Toplink):
Query query = entityManager.createNativeQuery("BEGIN PROCEDURE_NAME(); END;");
query.executeUpdate();
Die Variante mit geschweiften Klammern führte zu ORA-00900.
Folgendes funktioniert für mich:
Query query = em.createNativeQuery("BEGIN VALIDACIONES_QPAI.RECALC_COMP_Assembly('X','X','X',0); END;");
query.executeUpdate();
Für eine einfache gespeicherte Prozedur, die IN/OUT-Parameter wie folgt verwendet
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;
Sie können es von JPA aus wie folgt aufrufen:
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);
Für eine gespeicherte Prozedur, die einen SYS_REFCURSOR
OUT-Parameter verwendet:
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;
Sie können es wie folgt aufrufen:
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();
Für eine SQL-Funktion, die wie folgt aussieht:
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;
Man kann es so nennen:
BigDecimal commentCount = (BigDecimal) entityManager
.createNativeQuery(
"SELECT fn_count_comments(:postId) FROM DUAL"
)
.setParameter("postId", 1L)
.getSingleResult();
Zumindest bei Verwendung von Hibernate 4.x und 5.x, da die JPA StoredProcedureQuery
nicht für SQL-FUNKTIONEN funktioniert.
Weitere Informationen zum Aufrufen von gespeicherten Prozeduren und Funktionen bei Verwendung von JPA und Ruhezustand finden Sie in den folgenden Artikeln
Das hat bei mir funktioniert.
@Entity
@Table(name="acct")
@NamedNativeQueries({
@NamedNativeQuery(callable=true, name="Account.findOne", query="call sp_get_acct(?), resultClass=Account.class)})
public class Account{
// Code
}
Hinweis: Wenn Sie sich in Zukunft für die Verwendung der Standardversion von findOne entscheiden, kommentieren Sie einfach die Annotation NamedNativeQueries und JPA wird auf die Standardeinstellung gesetzt
Vielleicht ist es für Sql Srver nicht dasselbe, aber für Leute, die Oracle und Eclipslink verwenden, funktioniert es für mich
beispiel: eine Prozedur mit einem IN-Parameter (Typ CHAR) und zwei OUT-Parametern (NUMBER & VARCHAR)
in der persistence.xml deklarieren Sie die Persistence-Unit:
<persistence-unit name="presistanceNameOfProc" transaction-type="RESOURCE_LOCAL">
<provider>org.Eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/DataSourceName</jta-data-source>
<mapping-file>META-INF/eclipselink-orm.xml</mapping-file>
<properties>
<property name="eclipselink.logging.level" value="FINEST"/>
<property name="eclipselink.logging.logger" value="DefaultLogger"/>
<property name="eclipselink.weaving" value="static"/>
<property name="eclipselink.ddl.table-creation-suffix" value="JPA_STORED_PROC" />
</properties>
</persistence-unit>
und deklarieren Sie die Struktur der proc in der Datei eclipselink-orm.xml
<?xml version="1.0" encoding="UTF-8"?><entity-mappings version="2.0"
xmlns="http://Java.Sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://Java.Sun.com/xml/ns/persistence/orm orm_2_0.xsd">
<named-stored-procedure-query name="PERSIST_PROC_NAME" procedure-name="name_of_proc" returns-result-set="false">
<parameter direction="IN" name="in_param_char" query-parameter="in_param_char" type="Character"/>
<parameter direction="OUT" name="out_param_int" query-parameter="out_param_int" type="Integer"/>
<parameter direction="OUT" name="out_param_varchar" query-parameter="out_param_varchar" type="String"/>
</named-stored-procedure-query>
im code musst du deinen proc einfach so aufrufen:
try {
final Query query = this.entityManager
.createNamedQuery("PERSIST_PROC_NAME");
query.setParameter("in_param_char", 'V');
resultQuery = (Object[]) query.getSingleResult();
} catch (final Exception ex) {
LOGGER.log(ex);
throw new TechnicalException(ex);
}
um die zwei Ausgangsparameter zu erhalten:
Integer myInt = (Integer) resultQuery[0];
String myStr = (String) resultQuery[1];
Diese Antwort kann hilfreich sein, wenn Sie über einen Entitätsmanager verfügen
Ich hatte eine gespeicherte Prozedur, um die nächste Nummer zu erstellen.
Client-Seite
Object on = entityManager.createNativeQuery("EXEC getNextNmber").executeUpdate();
log.info("New order id: " + on.toString());
Datenbankseite (SQL Server) Ich habe eine Prozedur mit dem Namen getNextNmber
gespeichert.
JPA 2.0 unterstützt keine RETURN-Werte, nur Aufrufe.
Meine Lösung war. Erstellen Sie eine FUNKTION, die PROCEDURE aufruft.
Innerhalb von Java-Code führen Sie also eine NATIVE QUERY aus, die Oracle FUNCTION aufruft.
Ab JPA 2.1 unterstützt JPA das Aufrufen gespeicherter Prozeduren mithilfe der dynamischen StoredProcedureQuery und der deklarativen @NamedStoredProcedureQuery.
Versuchen Sie diesen Code:
return em.createNativeQuery("{call getEmployeeDetails(?,?)}",
EmployeeDetails.class)
.setParameter(1, employeeId)
.setParameter(2, companyId).getResultList();
Sie können @Query(value = "{call PROC_TEST()}", nativeQuery = true)
in Ihrem Repository verwenden. Das hat bei mir funktioniert.
Achtung: verwende '{' und '}', sonst funktioniert es nicht.
persistence.xml
<persistence-unit name="PU2" transaction-type="RESOURCE_LOCAL">
<non-jta-data-source>jndi_ws2</non-jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties/>
codigo Java
String PERSISTENCE_UNIT_NAME = "PU2";
EntityManagerFactory factory2;
factory2 = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
EntityManager em2 = factory2.createEntityManager();
boolean committed = false;
try {
try {
StoredProcedureQuery storedProcedure = em2.createStoredProcedureQuery("PKCREATURNO.INSERTATURNO");
// set parameters
storedProcedure.registerStoredProcedureParameter("inuPKEMPRESA", BigDecimal.class, ParameterMode.IN);
storedProcedure.registerStoredProcedureParameter("inuPKSERVICIO", BigDecimal.class, ParameterMode.IN);
storedProcedure.registerStoredProcedureParameter("inuPKAREA", BigDecimal.class, ParameterMode.IN);
storedProcedure.registerStoredProcedureParameter("isbCHSIGLA", String.class, ParameterMode.IN);
storedProcedure.registerStoredProcedureParameter("INUSINCALIFICACION", BigInteger.class, ParameterMode.IN);
storedProcedure.registerStoredProcedureParameter("INUTIMBRAR", BigInteger.class, ParameterMode.IN);
storedProcedure.registerStoredProcedureParameter("INUTRANSFERIDO", BigInteger.class, ParameterMode.IN);
storedProcedure.registerStoredProcedureParameter("INTESTADO", BigInteger.class, ParameterMode.IN);
storedProcedure.registerStoredProcedureParameter("inuContador", BigInteger.class, ParameterMode.OUT);
BigDecimal inuPKEMPRESA = BigDecimal.valueOf(1);
BigDecimal inuPKSERVICIO = BigDecimal.valueOf(5);
BigDecimal inuPKAREA = BigDecimal.valueOf(23);
String isbCHSIGLA = "";
BigInteger INUSINCALIFICACION = BigInteger.ZERO;
BigInteger INUTIMBRAR = BigInteger.ZERO;
BigInteger INUTRANSFERIDO = BigInteger.ZERO;
BigInteger INTESTADO = BigInteger.ZERO;
BigInteger inuContador = BigInteger.ZERO;
storedProcedure.setParameter("inuPKEMPRESA", inuPKEMPRESA);
storedProcedure.setParameter("inuPKSERVICIO", inuPKSERVICIO);
storedProcedure.setParameter("inuPKAREA", inuPKAREA);
storedProcedure.setParameter("isbCHSIGLA", isbCHSIGLA);
storedProcedure.setParameter("INUSINCALIFICACION", INUSINCALIFICACION);
storedProcedure.setParameter("INUTIMBRAR", INUTIMBRAR);
storedProcedure.setParameter("INUTRANSFERIDO", INUTRANSFERIDO);
storedProcedure.setParameter("INTESTADO", INTESTADO);
storedProcedure.setParameter("inuContador", inuContador);
// execute SP
storedProcedure.execute();
// get result
try {
long _inuContador = (long) storedProcedure.getOutputParameterValue("inuContador");
varCon = _inuContador + "";
} catch (Exception e) {
}
} finally {
}
} finally {
em2.close();
}
Um eine gespeicherte Prozedur aufzurufen, können wir die Callable-Anweisung im Java.sql-Paket verwenden.