2014-09-30 17 views
5

Tôi đang sử dụng Spring MVC 4, Hibernate và PostgreSQL 9,3 và đã xác định chức năng (stored procedure) bên trong Postgres như thế này:Làm thế nào để gọi đúng các hàm PostgreSQL (các thủ tục lưu sẵn) trong Spring/Hibernate/JPA?

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; 

Nếu tôi chạy chức năng này bên pgAdmin như thế này nó làm việc tốt:

select spa.create_tenant('somename'); 

Bây giờ tôi đang cố gắng để chạy chức năng này từ dịch vụ của tôi như thế này:

@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(); 
} 

Nếu tôi chạy phương pháp của tôi tôi nhận được lỗi sau:

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

Tôi đoán đây là vì lợi nhuận kiểu void được xác định trong chức năng vì vậy tôi đã thay đổi kiểu trả về để trông như thế này:

RETURNS character varying AS 

Nếu tôi chạy phương pháp của tôi một lần nữa tôi nhận được ngoại lệ này thay thế:

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

Có ai biết điều gì đang xảy ra ở đây và cách gọi đúng thủ tục lưu trữ trong PostgreSQL ngay cả khi không có loại trả về?

+0

Làm thế nào bạn thường gọi là JDBC CallableStatement? Đó là tất cả các API JPA kết thúc tốt đẹp. Nếu Hibernate không phản chiếu những gì JDBC cung cấp thì hãy thử một nhà cung cấp JPA khác để xem cách xử lý nó như thế nào –

Trả lời

1

Vì bạn đang sử dụng PostgreSQL, bạn có thể, như bạn đã viết, hãy gọi bất kỳ thủ tục lưu trữ kiểu chức năng trong SELECT (Oracle, nếu không, sẽ cho phép bạn chỉ thực hiện chức năng tuyên bố là chỉ đọc trong các lựa chọn).

Bạn có thể sử dụng EntityManager.createNativeQuery(SQL).

Vì bạn đang sử dụng Spring, bạn có thể sử dụng SimpleJdbcTemplate.query(SQL) để thực thi bất kỳ câu lệnh SQL nào.

+0

Làm thế nào để gọi hàm và nhận kết quả tại bộ điều khiển? Xem http://stackoverflow.com/q/41864288/287948 –

2

Trong lớp tổ chức của bạn, hãy xác định một NamedNativeQuery giống như bạn sẽ gọi hàm postgresql với chọn.

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 

ngủ đông không có khả năng lập bản đồ bãi bỏ, do đó, một workaround là để đúc kết quả dưới dạng văn bản

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

truy vấn này không biên dịch –

+1

Xin lỗi @AlexG để trả lời muộn, tôi đã chỉnh sửa đề xuất mã Thực thể, nhưng tôi hy vọng bạn đã tìm thấy giải pháp – srex

1

Tôi nghĩ rằng đó là RETURN VOID đó là gây ra vấn đề. Có an article on this topic có thể giúp bạn cũng như:

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; 

Sau khi bạn đã thay đổi chức năng của bạn để trở lại một số giá trị giả, thay đổi truy vấn thủ tục lưu trữ như sau:

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

Cách gọi hàm và nhận được kết quả tại bộ điều khiển?Xem http://stackoverflow.com/q/41864288/287948 –

Các vấn đề liên quan