2012-09-24 2 views
9

내가 문제가되는 곳 : org.hibernate.MappingException : 아니요 1111 JPA 기본 쿼리를 사용하여 postgres 함수를 호출하려고 할 때 JDBC 유형에 대한 Dialect 매핑이 없습니다. .JPA Hibernate Call Postgres Function Void 반환 MappingException :

시동 싱글 톤에 EJB 타이머를 만들어 6 시간마다 Postgres 기능을 실행했습니다. 이 함수는 void를 반환하고 만료 된 레코드를 확인하고, 삭제하고, 일부 상태를 업데이트합니다. 인수를 취하지 않고 void를 반환합니다.

  • 포스트그레스 기능을 완벽하게 나는 그것이 PgAdmin 쿼리 도구 사용하여 호출하는 경우 실행 (선택 기능();) void를 반환합니다.

  • Glassfish 3.1.1에서 응용 프로그램을 배포 할 때 예외가 발생하고 배포하지 못했습니다.

    먼저 JPA 물건 : 싱글이 그것을 호출

    public void runRequestCleanup() { 
        String queryString = "SELECT a_function_that_hibernate_chokes_on()"; 
        Query query = em.createNativeQuery(queryString); 
        Object result = query.getSingleResult(); 
    } 
    

    이 여기

    WARNING: A system exception occurred during an invocation on EJB UserQueryBean method public void com.mysoftwareco.entity.utility.UserQueryBean.runRequestCleanup() 
    javax.ejb.TransactionRolledbackLocalException: Exception thrown from bean 
    ...STACK TRACE BLAH BLAH BLAH ... 
    Caused by: javax.persistence.PersistenceException: org.hibernate.MappingException: No Dialect mapping for JDBC type: 1111 
    

    코드입니다 :

은 (단축) 스택 추적입니다 :

@Startup 
@Singleton 
public class RequestCleanupTimer { 
    @Resource 
    TimerService timerService; 
    @EJB 
    UserQueryBean queryBean; 

    @PostConstruct 
    @Schedule(hour = "*/6") 
    void runCleanupTimer() { 
     queryBean.runRequestCleanup(); 
    } 
} 

그리고 기능 :

CREATE OR REPLACE FUNCTION a_function_that_hibernate_chokes_on() 
    RETURNS void AS 
$BODY$ 
    DECLARE 
     var_field_id myTable.field_id%TYPE; 
    BEGIN 
     FOR var_field_id IN 
       select field_id from myTable 
       where status = 'some status' 
       and disposition = 'some disposition' 
       and valid_through < now() 
     LOOP 
      BEGIN 
       -- Do Stuff 
      END; 
     END LOOP; 
    END; 
$BODY$ 
    LANGUAGE plpgsql VOLATILE 
    COST 100; 

답변

3

내가 충분히 JPA가 저장 프로 시저를 실행하려고 노력으로 장난했다.

JDBC를 사용하여 준비된 문을 사용하여 작업을 마쳤습니다. 둥근 구멍에 정사각형 못을 끼워 넣으려고 노력하는 몇 시간을 보내고 난 후 15 분 안에 그것을했습니다. 지속성 유닛이 연결을 얻는 데 사용하는 것과 동일한 jndi 데이터 소스를 호출하고, 준비된 명령문을 작성한 후 완료했습니다.

그래서 당신이 저장 프로 시저를 실행해야하는 경우 (또는 포스트 그레스 기능)는 (지금 대부분) JPA 응용 프로그램에서, 여기에 나를 위해 일한 것입니다 :

@Stateless 
@LocalBean 
public class UserQueryBean implements Serializable { 

    @Resource(mappedName="jdbc/DatabasePool") 
    private javax.sql.DataSource ds; 

    ... 

    public void runRequestCleanup() { 

     String queryString = "SELECT cleanup_function_that_hibernateJPA_choked_on()"; 
     Connection conn = null; 
     PreparedStatement statement = null; 
     try { 
      conn = ds.getConnection(); 
      statement = conn.prepareCall(queryString); 
      statement.executeQuery(); 
     } catch (SQLException ex) { 
      Logger.getLogger(UserQueryBean.class.getName()).log(Level.SEVERE, null, ex); 
     }finally{ 
      try { 
       statement.close(); 
       conn.close(); 
      } catch (SQLException ex) { 
       Logger.getLogger(UserQueryBean.class.getName()).log(Level.SEVERE, null, ex); 
      } 
     } 
     // bit of logging code here  
    } 
    ... 
} 

떠나 끔찍한 감독이 될 것 같다 JPA에서 서버에 기능이나 저장 프로 시저를 실행하는 간단한 기능을 제공합니다. 특히 void 또는 영향을받는 행의 수를 제외하고는 아무것도 반환하지 않습니다. 그리고 그것이 고의적이라면 ... 아무런 언급이 없습니다.

편집 : 추가 연결 닫기.

1

이것은 얼마 전에 게시되었지만 비슷한 문제가있었습니다. 명시된 바와 같이, Hibernate는 알레르기 반응을 보였으며 매번 리턴 타입을 사용하도록 당신을 고정 시키려고 할 것이다. 내 관점에서 볼 때, 이것은 일반적으로 항상 성공 여부를 지정하기 위해 항상 반환해야하는 것처럼 좋은 방법입니다. 던지는 예외는 종종 까다 롭습니다.

그러나, 최대 절전 모드는 제한이있어 우회 할 수있는 방법을 제공합니까 : org.hibernate.jdbc.Work

할 수 있습니다 쉽게 작은 클래스에 필요한 있었는지 재현 : 당신이 사용하여 원할 때마다

class VoidProcedureWork implements Work { 

    String query; 

    private VoidProcedureWork(String sql) { 
     query = sql; 
    } 

    public static boolean execute(Session session, String sql) { 
     try { 
      // We assume that we will succeed or receive an exception. 
      session.doWork(new VoidProcedureWork(sql)); 
      return true; 
     } catch (Throwable e) { 
      // log exception 
      return false; 
     } 
    } 

    /** 
    * @see org.hibernate.jdbc.Work#execute(java.sql.Connection) 
    */ 
    @Override 
    public void execute(Connection connection) throws SQLException { 
     Statement statement = null; 
     try { 
      statement = connection.createStatement(); 
      statement.execute(query); 
     } finally { 
      if (statement != null) 
       statement.close(); 
     } 
    } 
} 

지금 당신이 그것을 호출 할 수 있습니다

VoidProcedureWork.execute (hibernateSession, sqlQuery);

이 클래스에 대해 두 가지 사항을 알게 될 것입니다. 1) Connection을 닫지 마십시오. Connection을 누가 열었는지, 왜, 어떻게했는지 모르기 때문에 나는 그 방식으로 남겨 둡니다. 거래에서 동일한 연결이 사용됩니까? 내가 그것을 닫으면 누군가가 그것을 사용한다. 충돌 할까? 내가 Hibernate를 코딩하지 않았고 connection.open()을 사용하지 않았다. 그러므로 나는 그것을 닫지 않고 어떤 것이 든 그것을 닫을 것이라고 생각한다. 2) OOP보다 절차적인 프로그래밍입니다. 나도 알아,하지만 게으르다. 새로운 VoidProcedureWork (SQL) .execute (session)보다 VoidProcedureWork.execute (session, sql)를 사용하는 것이 더 쉽다. 또는 최악의 경우 : 예외 처리와 함께 그 작은 트릭 (session.doWork (new VoidProcedureWork (sql))을 사용하려고 할 때마다 실행 코드를 재생산하십시오.

11

이것은 해킹 일 수 있지만 나에게 효과적이며 매우 간단합니다. 쿼리를 다음으로 변경하십시오.

SELECT count(*) FROM your_function(); 

이제는 적절한 정수를 반환하고 최대 절전 모드가 행복합니다.

+0

아주 좋습니다. 나는 다른 대답을보고 너의 것이 최고라고 생각한다. – luizcarlosfx

+0

당신과 @ Kikin-Sama의 방법이 모두 효과가있었습니다. – BillR

0

Dude! 함수 이름을 인용하는 것만 큼 쉽습니다. 좋아요 :

public void runRequestCleanup() { 
    String queryString = "SELECT \"a_function_that_hibernate_chokes_on\"()"; 
    Query query = em.createNativeQuery(queryString); 
    Object result = query.getSingleResult(); 
} 
1

이번 호의 향후 방문객을 위해 캐스팅 한 사람도 사용할 수 있습니다. this thread도 게시

public void runRequestCleanup() { 
    String queryString = "SELECT cast(a_function_that_hibernate_chokes_on() as text)"; 
    Query query = em.createNativeQuery(queryString); 
    query.getSingleResult(); 
} 
2

postgres 저장 프로 시저가 void를 반환하면 문제가 발생하는 것 같습니다. 일부 더미 값 (아마도 문자열)을 반환하도록 반환 유형을 변경하십시오. 내 경우 엔 효과가 있었어.

+0

void를 반환하는 postgres의 admin 함수를 호출하려고합니다. pg_advisory_xact_lock은 내가 부르는 것이다. 내가 어떻게 바꿀 수 있니? – faizan