13

次の問題が発生します:org.hibernate.MappingException: JPA create native queryを使用してpostgres関数を呼び出そうとすると、JDBCタイプのダイアレクトマッピングがありません:1111。

スタートアップシングルトンにEJBタイマーを作成して、6時間ごとにPostgres関数を実行しました。この関数はvoidを返し、期限切れのレコードをチェックして削除し、いくつかのステータスを更新します。引数をとらず、voidを返します。

  • postgres関数は、PgAdminクエリツール(select function();)を使用して呼び出すと完全に実行され、voidを返します。

  • Glassfish 3.1.1にアプリをデプロイすると、例外が発生し、デプロイに失敗します。

これは(短縮された)スタックトレースです:

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

コードは次のとおりです。

まず、JPAのもの:

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

これは、それを呼び出すシングルトンです。

@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;
4

7 に答える 7

29

これはハックかもしれませんが、私にとってはうまくいき、とても簡単です。クエリを次のように変更するだけです。

SELECT count(*) FROM your_function();

これで適切な整数が返され、Hibernateは満足しています。

于 2013-08-26T08:02:10.413 に答える
5

ストアドプロシージャを実行するためにJPAを取得しようとして、JPAをいじくり回しました。

プリペアドステートメントでJDBCを使用することになりました。四角いペグを丸い穴に合わせようとして何時間も無駄な時間を費やした後、15分でそれを行いました。永続化ユニットが接続を取得するために使用するのと同じjndiデータソースを呼び出し、プリペアドステートメントを作成し、完了したらそれを閉じました。

したがって、(現在はほとんど)JPAアプリからストアドプロシージャ(またはPostgres関数)を実行する必要がある場合は、次のようになります。

@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または影響を受ける行数以外は何も返さないもの。そしてそれが意図的だった場合...コメントはありません。

編集:密接な接続を追加しました。

于 2012-09-24T19:59:36.003 に答える
3

この問題の将来の訪問者のために、キャストも働いていただろう。このスレッドにも投稿されています

public void runRequestCleanup() {
    String queryString = "SELECT cast(a_function_that_hibernate_chokes_on() as text)";
    Query query = em.createNativeQuery(queryString);
    query.getSingleResult();
}
于 2015-08-24T20:22:16.803 に答える
2

postgresストアドプロシージャがvoidを返すときに問題が発生するようです。戻り型を変更して、ダミー値(おそらく文字列)を返すようにしてください。私の場合、これはうまくいきました。

于 2016-02-02T17:28:06.257 に答える
1

これは少し前に投稿されましたが、私も同様の問題を抱えていました。述べたように、Hibernateは無効にアレルギーがあるように見え、毎回returnタイプを使用するようにロックしようとします。私の観点からは、これは良い習慣です。通常、少なくとも成功したかどうかを指定するために常にリターンが必要です。例外をスローすると、多くの場合、悪用されます。

それでも、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);

このクラスについて2つのことに気付くでしょう:1)私は接続を閉じません。誰が、どのように、そしてなぜ接続を開いたのかわからないので、そのままにしておきます。トランザクションで同じ接続が使用されていますか?私がそれを閉じて、誰かが後でそれを使用した場合、それはクラッシュしますか?など私はHibernateをコーディングせず、connection.open()を使用しませんでした。したがって、私はそれを閉じず、開いたものは何でもそれを閉じると思います。2)OOPよりも手続き型プログラミングです。私は知っていますが、私は怠惰です:新しいVoidProcedureWork(sql).execute(session)よりもVoidProcedureWork.execute(session、sql)を使用する方が簡単です(そしてより明確なimo)。またはさらに最悪の場合:その小さなトリックを使用するたびに実行のコードを再現します(例外処理を伴うsession.doWork(new VoidProcedureWork(sql)))。

于 2013-01-03T19:13:55.603 に答える
0

お前!関数名を引用するのと同じくらい簡単です。そのようです:

public void runRequestCleanup() {
    String queryString = "SELECT \"a_function_that_hibernate_chokes_on\"()";
    Query query = em.createNativeQuery(queryString);
    Object result = query.getSingleResult();
}
于 2014-06-11T20:49:26.750 に答える
-1

クエリを:に変換します

SELECT cast(sqlFunction() as text)

例:"SELECT cast(pushlogsToMainTable() as text)"

それは私のために働いた。

于 2020-05-20T20:50:49.490 に答える