How to properly call PostgreSQL functions (stored procedures) within Spring/Hibernate/JPA?

前端 未结 6 1328
孤城傲影
孤城傲影 2021-01-12 04:11

I\'m using Spring MVC 4, Hibernate and PostgreSQL 9.3 and have defined function (stored procedure) inside Postgres like this:

CREATE OR REPLACE FUNCTION spa.         


        
相关标签:
6条回答
  • 2021-01-12 04:12
    • PostgreSQL
    • Hibernate
    • Kotlin

    CREATE OR REPLACE FUNCTION your_procedure() RETURNS text AS $$
    BEGIN
        RETURN 'Some text';
    END;
    $$ LANGUAGE plpgsql;
    

    val query = session.createNativeQuery("SELECT your_procedure()")
    query.list().map {
        println("NativeQuery: $it")
    }
    
    0 讨论(0)
  • 2021-01-12 04:28

    In case you are using also spring data, you could just define a procedure inside your @Repository interface like this,

    @Procedure(value = "spa.create_tenant")
    public void createTenantOrSomething(@Param("t_name") String tNameOrSomething);
    

    More in the docs.

    0 讨论(0)
  • 2021-01-12 04:29

    If you want to keep it simple, just do this:

        em.createSQLQuery("SELECT * FROM spa.create_tenant(:t_name) ")
                              .setParameter("t_name", name)").list();
    

    Notice I used list() intentionally.. for some reason .update() didn't work for me.

    0 讨论(0)
  • 2021-01-12 04:30

    Since you're using PostgreSQL, you can, as you've already written, call any stored procedure of type function in SELECT (Oracle, otherwise, would let you only execute functions declared to be read only in selects).

    You can use EntityManager.createNativeQuery(SQL).

    Since you're using Spring, you can use SimpleJdbcTemplate.query(SQL) to execute any SQL statement, as well.

    0 讨论(0)
  • 2021-01-12 04:37

    I think it's the RETURN VOID that's causing the issue. So, changed the FUNCTION definition like this:

    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;
    

    After you changed your function to return some dummy value, change the stored procedure query to this:

    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 讨论(0)
  • 2021-01-12 04:39

    In your entity class, define a NamedNativeQuery like you would call postgresql function with select.

    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 is not able to map void, so a workaround is to cast result as text

    public void createSchema(String name) {
        Query query = em.createNamedQuery("Tenant.createTenant")
                .setParameter(1, name);
        query.getSingleResult();
    }
    
    0 讨论(0)
提交回复
热议问题