2014-09-30 7 views
5

Ich verwende Spring MVC 4, Hibernate und PostgreSQL 9.3 und haben Funktion (Stored Procedure) innerhalb Postgres wie folgt definiert:Wie werden PostgreSQL-Funktionen (gespeicherte Prozeduren) in Spring/Hibernate/JPA korrekt aufgerufen?

CREATE OR REPLACE FUNCTION spa.create_tenant(t_name character varying) 
    RETURNS void AS 
    $BODY$ 
    BEGIN 
     EXECUTE format('CREATE SCHEMA IF NOT EXISTS %I AUTHORIZATION postgres', t_name); 
    END 
    $BODY$ 
    LANGUAGE plpgsql VOLATILE 
    COST 100; 
ALTER FUNCTION spa.create_tenant(character varying) 
OWNER TO postgres; 

Wenn ich diese Funktion in pgAdmin wie folgt ausführen es funktioniert gut:

select spa.create_tenant('somename'); 

Jetzt versuche ich, diese Funktion von meinem Dienst wie folgt auszuführen:

@Override 
@Transactional 
public void createSchema(String name) { 
    StoredProcedureQuery sp = em.createStoredProcedureQuery("spa.create_tenant"); 
    sp.registerStoredProcedureParameter("t_name", String.class, ParameterMode.IN); 
    sp.setParameter("t_name", name); 
    sp.execute(); 
} 

Wenn ich meine Methode ausführen ich folgende Störung zu erhalten:

javax.persistence.PersistenceException: org.hibernate.MappingException: No Dialect mapping for JDBC type: 1111 

ich dies zu raten ist, weil der Rückgabetyp Leere, die in Funktion definiert ist, so änderte ich Typ zurückgeben wie folgt aussehen:

RETURNS character varying AS 

Wenn ich meine Methode laufen wieder erhalte ich statt diese Ausnahme:

javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: Error calling CallableStatement.getMoreResults 

weiß jemand, was hier vor sich geht und wie man richtig gespeicherte Prozeduren in PostgreSQL rufen auch bei Leere als Rückgabetyp?

+0

Wie würden Sie ein JDBC-Callablestatement nennen? Das ist alles, was die JPA-API umschließt. Wenn Hibernate nicht das widerspiegelt, was JDBC gibt, versuchen Sie einen anderen JPA-Provider, um zu sehen, wie dieser behandelt wird. –

Antwort

1

Da Sie verwenden PostgreSQL, Sie können, wie Sie bereits geschrieben haben, rufen Sie jede gespeicherte Prozedur vom Typ Funktion in SELECT (Oracle, sonst würden Sie nur Funktionen erklärt ausführen zu sein nur in Auswahlen lesen).

Sie können EntityManager.createNativeQuery(SQL) verwenden.

Da Sie Spring verwenden, können Sie auch SimpleJdbcTemplate.query(SQL) verwenden, um eine beliebige SQL-Anweisung auszuführen.

+0

Wie kann man die Funktion aufrufen und das Ergebnis am Controller bekommen? Siehe http://StackOverflow.com/q/41864288/287948 –

2

Definieren Sie in Ihrer Entitätsklasse eine NamedNativeQuery, wie Sie die postgresql-Funktion mit select aufrufen würden.

import javax.persistence.NamedNativeQueries; 
import javax.persistence.NamedNativeQuery; 
import javax.persistence.Entity; 
@NamedNativeQueries(
    value={ 
      // cast is used for Hibernate, to prevent No Dialect mapping for JDBC type: 1111 
      @NamedNativeQuery(
        name = "Tenant.createTenant", 
       query = "select cast(create_tenant(?) as text)" 
      ) 
    } 
) 
@Entity 
public class Tenant 

Hibernate ist nicht in der Lage Leere Karte, so dass eine Abhilfe ist Ergebnis als Text

public void createSchema(String name) { 
    Query query = em.createNamedQuery("Tenant.createTenant") 
      .setParameter(1, name); 
    query.getSingleResult(); 
} 
+0

Diese Abfrage kompiliert nicht –

+1

Sorry @AlexG für späte Antwort, ich habe Entitätscode Vorschlag bearbeitet, aber ich hoffe, Sie haben bereits die Lösung gefunden – srex

1

Ich denke, es ist die RETURN VOID, das verursacht das Problem zu werfen. Es gibt an article on this topic, die Ihnen auch helfen können:

CREATE OR REPLACE FUNCTION spa.create_tenant(t_name character varying) 
    RETURNS bigint AS 
    $BODY$ 
    BEGIN 
     EXECUTE format('CREATE SCHEMA IF NOT EXISTS %I AUTHORIZATION postgres', t_name); 
     RETURN 1; 
    END 
    $BODY$ 
    LANGUAGE plpgsql VOLATILE 
    COST 100; 
ALTER FUNCTION spa.create_tenant(character varying) 
OWNER TO postgres; 

Nachdem Sie Ihre Funktion geändert einig Dummy-Wert zurückzukehren, ändern Sie die gespeicherte Prozedur Abfrage dazu:

StoredProcedureQuery query = entityManager 
    .createStoredProcedureQuery("spa.create_tenant") 
    .registerStoredProcedureParameter(1, 
     Long.class, ParameterMode.OUT) 
    .registerStoredProcedureParameter(2, 
     String.class, ParameterMode.IN) 
    .setParameter(2, name); 

query.getResultList(); 
+0

Wie Sie die Funktion aufrufen und bekomme das Ergebnis bei der Steuerung?Siehe http://stackoverflow.com/q/41864288/287948 –

Verwandte Themen