使用MyBatis调用Oracle存储过程

6

我正在将我们的数据库从SQL Server 2008迁移到Oracle,但无法使MyBatis工作。

以下是示例:

UserMapper.xml(示例)

<resultMap type="User" id="UserResult">
    <id property="userId" column="userId"/>
    <result property="firstName" column="firstName"/>
    <result property="lastName" column="lastName"/>
</resultMap>

<select id="getUsers" statementType="CALLABLE" resultMap="UserResult">
    {CALL GetUsers()}
</select>

UserDAO.java

public interface UserDAO {
    public List<User> getUsers();
}

SQL Server存储过程

CREATE PROCEDURE [dbo].[GetUsers]
AS
BEGIN
    SET NOCOUNT ON;
    SELECT userId, firstName, lastName
    FROM Users
END

...在 SQL Server 2008 中有效。请问有人可以告诉我如何从 UserMapper.xml 中调用与上述 SQL Server 存储过程相同名称和列的 Oracle 存储过程,并使用 Oracle 游标填充我的 User 类吗?

这是我尝试的方法:

<resultMap type="User" id="UserResult">
    <id property="userId" column="userId"/>
    <result property="firstName" column="firstName"/>
    <result property="lastName" column="lastName"/>
</resultMap>

<select id="getUsers" statementType="CALLABLE" resultMap="UserResult">
    {CALL GetUsers(#{resultSet,mode=OUT,jdbcType=CURSOR,resultMap=UserResult})}
</select>

我遇到了以下错误:

Caused by: org.apache.ibatis.reflection.ReflectionException: 
Could not set property 'resultSet' of 'class java.lang.Class'
with value 'oracle.jdbc.driver.OracleResultSetImpl@476d05dc' 
Cause: org.apache.ibatis.reflection.ReflectionException: 
There is no setter for property named 'resultSet' in 'class java.lang.Class'
4个回答

9

结果映射如下:

<resultMap id="UserResult" type="User">
    <id property="userId" column="userId"/>
    <result property="firstName" column="firstName"/>
    <result property="lastName" column="lastName"/>     
</resultMap>

在您的选择语句中,将参数类型更改为java.util.Map。
<select id="getUsers" statementType="CALLABLE" parameterType="java.util.Map"> 
    {call GetUsers(#{users, jdbcType=CURSOR, javaType=java.sql.ResultSet, mode=OUT, resultMap=UserResult})} 
</select>

您的 Mapper 接口如下所示,看起来您目前称之为 DAO。我过去的做法是创建一个 Mapper 接口,将其注入到 DAO 中,然后 DAO 调用 Mapper 上的方法。以下是示例 Mapper 接口:

public interface UserMapper {
    public Object getUsers(Map<String, Object> params);
}

那个映射器类将被注入到DAO类中,并像这样进行调用:
public List<User> getUsers() {
    Map<String, Object> params = new HashMap<String, Object>(); 
    ResultSet rs = null;
    params.put("users", rs);
    userMapper.getUsers(params);
    return ((ArrayList<User>)params.get("users"));
}

1
谢谢clav。我尝试了你的例子,但是我得到了与上面第2行相同的错误:“无法设置'java.lang.Class'类的'resultSet'属性。”有什么想法吗? - snoozy
1
我记不起确切的语法了。我对此感同身受,因为我大约一年前也经历过这种情况。我找到了一些我保存下来的示例代码并更新了我的答案,你可以试试看。 - clav
1
太棒了!非常感谢您的回答,应该是在搜索“无法设置java.lang.Class类的属性”时出现的第一条结果。非常感谢! - xandermonkey
1
@clav 你是个英雄(如果你是女性则为女英雄)。我花了一整天的时间来寻找这个解决方案。这个方法完美地解决了问题。 - myhouse

1
从Oracle 11中使用MyBatis/iBATIS 3获取结果集是一个非常奇怪的过程。我觉得这没有任何意义,但它确实有效。我的示例有所不同,但你会明白的。
create or replace 
PROCEDURE SP_GET_ALL_STORED_PROC (l_cursor out SYS_REFCURSOR) IS
BEGIN
open l_cursor for select account_id, totalLegs, born, weight, mammal, animal from copybittest;
END SP_GET_ALL_STORED_PROC;

Map map = new HashMap();
session.selectList("ibatis_3_test.selectProductAllOracleStoredProc", map); 
List productList = (List) map.get("key");

<resultMap id="productResultMap" type="test.Product">
</resultMap>

<select id="selectProductAllOracleStoredProc" parameterType="java.util.Map" statementType="CALLABLE">
    {call SP_GET_ALL_STORED_PROC(#{key, jdbcType=CURSOR, mode=OUT, javaType=java.sql.ResultSet,resultMap=productResultMap})}
</select>

1

作为对clav评论的补充,Snoozy,你需要从中删除resultSet。

<select id="getUsers" statementType="CALLABLE" resultMap="UserResult">
    {CALL GetUsers(#    {resultSet,mode=OUT,jdbcType=CURSOR,resultMap=UserResult})}

将其更改为“key”,如下:

<select id="getUsers" statementType="CALLABLE" resultMap="UserResult">
    {CALL GetUsers(#{key,mode=OUT,jdbcType=CURSOR,resultMap=UserResult})}
</select>

我希望这对您有所帮助。


0

我也遇到了同样的错误。

原因:org.apache.ibatis.reflection.ReflectionException:在类java.lang.Class中没有名为'columnNames'的属性设置器

位于mapper.java文件的getSearchResult(searchCriteriaVO vo)方法内

位于mapper.xml文件中

  #{userId, mode=IN, jdbcType=VARCHAR},
    #{resultList, mode=OUT, jdbcType=CURSOR, javaType=ResultSet,  resultMap=inquiryResult},

其中 inquiryResult 被定义为

<resultMap type="java.util.LinkedHashMap" id="inquiryResult">
<result property="name" jdbcType="VARCHAR" javaType="String" column="name"/>

挣扎了一整天,但当我调试时,发现只是一个简单的错误。我的值对象传递给了我的映射器类为空值。即使我的VO为空,MyBatis也会将其作为null传递给查询。但是当MyBatis尝试将结果设置到我的VO时,由于它是null,所以会抛出上述错误。

希望这些信息对您有用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接