使用jdbi

时间:2018-07-19 12:06:57

标签: ojdbc jdbi

我正在通过JDBC使用JDBI连接到Oracle数据库。我们有存储过程,可以将用户定义的对象作为out参数返回。我可以使用JDBC来调用它,但是看不到如何使用JDBI。

示例,假设我在数据库中将对象定义为

create or replace type myObj as object
   ( id           varchar2(11),
     text         varchar2(4000) )
/

我有一个带有功能的包装

FUNCTION foo ( pId in varchar2, pMyObj_o out myObj )
RETURN NUMBER IS
...

然后,使用JDBI,我可以这样称呼它:

String sql = "{ ? = call my_package.foo(?, ?) }";
CallableStatement cstmt = getConnection().prepareCall(sql);
cstmt.registerOutParameter(1, oracle.jdbc.OracleTypes.INTEGER);
cstmt.setString(2, 1);
cstmt.registerOutParameter(3, oracle.jdbc.OracleTypes.STRUCT, "MYSCHEMA.MYOBJ");

但是,我看不到如何使用命名参数对JDBI进行此操作。 JDBI似乎有两个版本registerOutParameter。基本的只是一个ID和类型,但是如果我叫它

String sql = "{ :numRows = call my_package.foo(:id, :obj) }";
Integer num = getJdbi().withHandle( handle -> { 
   OutParameters outParams = handle.createCall(sql)
     .bind("id", "1")
     .registerOutParameter("obj", Types.STRUCT)
     .invoke();

   return outParams.getInt("numRows"); 
});

然后我得到一个错误 org.jdbi.v3.core.statement.UnableToCreateStatementException:绑定命名参数obj时发生异常

唯一的选择是registerOutParameter,它带有第三个参数CallableStatementMapper,但我真的找不到如何使用它的任何示例。

我试图定义一个类

public class ObjRecErrMsg implements SQLData {
    private String sQLTypeName;
    private String id;
    private String text;

    public ObjRecErrMsg() {}

    public ObjRecErrMsg(String SqlType, String Id, String Text) {
        this.sQLTypeName = SqlType;
        this.id = Id;
        this.text = Text;
    }

    @Override
    public String getSQLTypeName() throws SQLException {
        return sQLTypeName;
    }
    @Override
    public void readSQL(SQLInput stream, String typeName) throws SQLException {
        sQLTypeName = typeName;
        id = stream.readString();
        text = stream.readString();
    }
    @Override
    public void writeSQL(SQLOutput stream) throws SQLException {
        stream.writeString(getId());
        stream.writeString(getText());
    }

    public String getId() {
        return id;
    }
    public String getText() {
        return text;
    }
}

如果我随后将该映射添加到连接中,则可以使用它,并且它可以与JDBC一起使用:

Connection conn = getConnection();
Map<String, Class<?>> newMap = conn.getTypeMap();
if( newMap == null ) {
    newMap = new HashMap<String, Class<?>>();
}
newMap.put(MYSCHEMA.MYOBJ", MyObj.class);
conn.setTypeMap(newMap);
String sql = "{ ? = call my_package.foo(?, ?) }";
CallableStatement cstmt = conn.prepareCall(sql);
cstmt.registerOutParameter(1, oracle.jdbc.OracleTypes.INTEGER);
cstmt.setString(2, 1);
cstmt.registerOutParameter(3, oracle.jdbc.OracleTypes.STRUCT, "MYSCHEMA.MYOBJ");

并将对象作为

msg = (MyObj)cstmt.getObject(3);

但是,当我尝试如下定义CallableStatementMapper时:

public class ObjWrapper implements CallableStatementMapper {

    public ObjWrapper() {
        // TODO Auto-generated constructor stub
    }

    @Override
    public Object map(int position, CallableStatement stmt) throws SQLException {
        return (MyObj) stmt.getObject(position);
    }    
}

并在JDBI调用中使用它:

String sql = "{ :numRows = call my_package.foo(:id, :obj) }";
Integer num = getJdbi().withHandle( handle -> { 
Map<String, Class<?>> newMap = handle.getConnection().getTypeMap();
    if( newMap == null ) {
        newMap = new HashMap<String, Class<?>>();
    }
    newMap.put("C20.OBJRECERRMSG", ObjRecErrMsg.class);
    handle.getConnection().setTypeMap(newMap);
    OutParameters outParams = handle.createCall(sql)
    .bind("id", "1")
    .registerOutParameter("obj", Types.STRUCT, new ObjWrapper ())
    .invoke();

    return outParams.getInt("numRows"); 
});

然后,在绑定命名参数时,我仍然会收到 Exception。

所以,主要问题是如何使用带有out参数(它是用户定义的对象)来调用存储过程?

子问题:

  • 如何在JDBI中指定类型(相当于JDBC调用中的第三个参数)
  • CallableStatementMapper的用途是什么?

0 个答案:

没有答案