Java 如何使用返回参数从Hibernate调用Oracle函数?

Java 如何使用返回参数从Hibernate调用Oracle函数?,java,oracle,hibernate,Java,Oracle,Hibernate,我的问题很像 我有一个函数,它在内部进行一些修改,并返回一个值 最初的想法是这样做: protected Integer checkXXX(Long id, Long transId) throws Exception { final String sql = "SELECT MYSCHEMA.MYFUNC(" + id + ", " + transId + ") FROM DUAL"; final BigDecimal nr = (Big

我的问题很像

我有一个函数,它在内部进行一些修改,并返回一个值

最初的想法是这样做:

protected Integer checkXXX(Long id, Long transId)
        throws Exception {
    final String sql = "SELECT MYSCHEMA.MYFUNC(" + id + ", "
            + transId + ") FROM DUAL";
    final BigDecimal nr = (BigDecimal) this.getHibernateTemplate()
            .getSessionFactory().getCurrentSession().createSQLQuery(sql)
            .uniqueResult();
    return nr.intValue();
}
session.doWork(new Work() {
   public void execute(Connection conn) {
      CallableStatement stmt = conn.prepareCall("? = call <some function name>(?)");
      stmt.registerOutParameter(1, OracleTypes.INTEGER);
      stmt.setInt(2, <some value>);
      stmt.execute();
      Integer outputValue = stmt.getInt(1);
      // And then you'd do something with this outputValue
   }
});
不幸的是,这不适用于Oracle。这样做的推荐方法是什么


有没有一种方法可以从我的语句中提取声明的变量?

Hibernate会话提供了一种方法,可以直接访问。然后,您可以创建并使用来执行您的函数:

session.doWork(new Work() {
  public void execute(Connection connection) throws SQLException {
    CallableStatement call = connection.prepareCall("{ ? = call MYSCHEMA.MYFUNC(?,?) }");
    call.registerOutParameter( 1, Types.INTEGER ); // or whatever it is
    call.setLong(2, id);
    call.setLong(3, transId);
    call.execute();
    int result = call.getInt(1); // propagate this back to enclosing class
  }
});

是的,您确实需要使用out参数。如果使用doWork()方法,您将执行以下操作:

protected Integer checkXXX(Long id, Long transId)
        throws Exception {
    final String sql = "SELECT MYSCHEMA.MYFUNC(" + id + ", "
            + transId + ") FROM DUAL";
    final BigDecimal nr = (BigDecimal) this.getHibernateTemplate()
            .getSessionFactory().getCurrentSession().createSQLQuery(sql)
            .uniqueResult();
    return nr.intValue();
}
session.doWork(new Work() {
   public void execute(Connection conn) {
      CallableStatement stmt = conn.prepareCall("? = call <some function name>(?)");
      stmt.registerOutParameter(1, OracleTypes.INTEGER);
      stmt.setInt(2, <some value>);
      stmt.execute();
      Integer outputValue = stmt.getInt(1);
      // And then you'd do something with this outputValue
   }
});
session.doWork(新工作(){
公共无效执行(连接连接){
CallableStatement stmt=conn.prepareCall(“?=call(?”);
注册表输出参数(1,OracleTypes.INTEGER);
stmt.setInt(2,);
stmt.execute();
整数outputValue=stmt.getInt(1);
//然后用这个输出值做一些事情
}
});
备选代码:)

若你们想要直接的结果,你们可以使用下面的代码

int result=session.doReturningWork(新的ReturningWork()){
@凌驾
公共整数执行(连接)引发SQLException{
CallableStatement call=connection.prepareCall(“{?=call MYSCHEMA.MYFUNC(?,)}”);
call.registerOutParameter(1,Types.INTEGER);//或其他类型
call.setLong(2,id);
call.setLong(3,transId);
call.execute();
return call.getInt(1);//将其传播回封闭类
}
});

您有以下选项:

  • 使用
    @namedNativeRequesty

     @org.hibernate.annotations.NamedNativeQuery(
         name = "fn_my_func",
         query = "{ ? = call MYSCHEMA.MYFUNC(?, ?) }",
         callable = true,
         resultClass = Integer.class
     )
    
     Integer result = (Integer) entityManager.createNamedQuery("fn_my_func")
         .setParameter(1, 1)
         .setParameter(2, 1)
         .getSingleResult();    
    
  • 使用JDBC API:

     Session session = entityManager.unwrap( Session.class );
    
     final AtomicReference<Integer> result = 
         new AtomicReference<>();
    
     session.doWork( connection -> {
         try (CallableStatement function = connection
                 .prepareCall(
                     "{ ? = call MYSCHEMA.MYFUNC(?, ?) }"
                 )
             ) {
             function.registerOutParameter( 1, Types.INTEGER );
             function.setInt( 2, 1 );
             function.setInt( 3, 1 );
             function.execute();
             result.set( function.getInt( 1 ) );
         }
     } );            
    

  • 你能举个例子吗?我有点不知道如何从函数中得到结果。我需要使用out参数吗?我在上面提供了一个示例。根据您的函数/存储过程的不同,您可能需要使用
    prepareCall()
    中的另一个调用表单-CallableStatement文档描述了这两种调用形式。@chsspy76:我从未听说过
    doWork(…)
    比Hibernate的
    @namedNativeRequesty
    好得多,后者要求存储过程/函数返回一个refcursor作为第一个参数(out参数)。@ChssPly76,正如我在下面提到的,我没有复制您的答案;我只是同时写的。我的帖子不值得投反对票。@chssly76,我和你同时写的,在我发布后,你的已经在那里了。它也不是一个精确的副本,尽管它当然非常相似,因为问题一开始就非常简单。如果你删除了你的反对票,那就太好了。SO上普遍接受的礼节是,如果你发现还有另外一个答案,那就删除你的答案,除非这两个答案是同时写的。在这种情况下,我的和你的相差16分钟。如果您现在删除它,由于否决投票而丢失的代表将在下次代表重新确认时恢复到您的帐户中(通常每6到8周进行一次)。除非你的答案经过编辑,否则否决票不能被撤销(太旧了)。在这种情况下,否决某人的投票也是普遍接受的礼仪吗?
    connection()
    方法在
    Hibernate 3.3.2GA+
    中被弃用,甚至
    connection()
    也被弃用。在这些版本中,这是您可以访问的方式。仅供参考:org.hibernate.MappingException:Unknown entity:java.lang.integery您可以翻阅我的书《高性能java持久化》和《GitHub存储库》等。我刚刚用Hibernate 5.2.11运行了它,它就像一个符咒一样工作。@Vladmichalcea在您的测试中没有“resultClass=Integer.class”GitHub@Alex这个答案是针对OP问题的,而我的GitHub存储库是针对不同的示例和用例的。
     Integer result = (Integer) entityManager.createNativeQuery(
         "SELECT MYSCHEMA.MYFUNC(:postId, :transId) FROM DUAL")
         .setParameter("postId", 1)
         .setParameter("transId", 1)
         .getSingleResult();