конфигурация аннотации mybatis для хранимой процедуры с результатом курсора

#java #mybatis #ibatis #spring-mybatis

Вопрос:

Я новичок в mybatis, и у меня есть вопрос.
У меня есть хранимая процедура Oracle, которая возвращает КУРСОР.

Я не понимаю, как я могу написать набор результатов с аннотациями.

Если я попробую это,

 @Mapper
public interface Message{

    @Select(value="{ #{OUT,javaType=java.sql.ResultSet,resultMap=messageQueryResult,jdbcType=CURSOR,mode=OUT} = call get_messages() }")
    @Options(statementType = StatementType.CALLABLE)
    @ResultMap("messageQueryResult")
    List<Message> getMessages();
}
 
 <mapper namespace="de.foo.mapper.Message">
    <resultMap id="messageQueryResult" type="de.foo.mapper.MessageValue">
    
            <result column="ID" javaType="java.lang.Long" />
            <result column="NOTE" javaType="java.lang.String" />

    </resultMap>
</mapper>
 
 public class MessageValue{

    private Long id;
    private String note;
}
 
 FUNCTION get_messages
  RETURN cursorType
  IS 
    c_messages  cursorType;
    sqlstring   VARCHAR2(4000);
  BEGIN
    sqlstring :=  'SELECT id, note FROM '||
                             ' vmessage WHERE ID IN ( ' ... ')';                                           

    OPEN cmessage FOR sqlstring;
    RETURN cmessage;
  END get_messages;
 

Я получаю сообщение об ошибке

 org.apache.ibatis.reflection.ReflectionException: There is no setter for property named 'OUT' in 'class java.lang.Class'
 

Что я делаю не так?
Есть ли возможность написать XML-картограф в аннотациях?

Комментарии:

1. В настоящее время MyBatis не поддерживает неявный курсор Oracle (т. е. DBMS_SQL.return_result ). Возможно, вам придется использовать OUT параметр для получения SYS_REFCURSOR . Вот исполняемая демонстрационная версия. Если вы не используете неявный курсор, пожалуйста, добавьте определение процедуры в вопрос.

2. Я добавил процедуру к вопросу

Ответ №1:

Тебе нужно кое-что исправить.

  1. Вы должны указать property атрибуты в результирующей карте.
     <resultMap id="messageQueryResult" type="de.foo.mapper.MessageValue">
      <result column="ID"  property="id" />
      <result column="NOTE" property="note" />
    </resultMap>
     
  2. Чтобы получить результат в качестве параметра OUT, методу необходим параметр.
    Я использую Map в качестве параметра. Вы можете использовать POJO со свойством out , если хотите.
    Кроме того, тип возвращаемого метода должен быть void и @ResultMap должен быть удален.

     @Select({
      "{ #{OUT,",
      "javaType=java.sql.ResultSet,", 
      "resultMap=messageQueryResult,", 
      "jdbcType=CURSOR,", 
      "mode=OUT} = call get_messages() }" })
    @Options(statementType = StatementType.CALLABLE)
    void getMessages(Map<String, Object> param);
     

После выполнения результат будет установлен в параметр, так что вот как вы его используете, в основном.

 Map<String, Object> param = new HashMap<>();
mapper.getMessages(param);
List<MessageValue> messages = (List<MessageValue>) param.get("OUT");
...
 

Я cursorType SYS_REFCURSOR , кстати, предположил, что это означает.


Что касается вашего последнего вопроса, можно определить карту результатов с помощью аннотаций @Results и @Result (документация здесь).
Ваш случай немного сложнее, потому что MyBatis использует тип возвращаемого значения аннотированного метода при построении карты результатов. Таким образом, вместо метода аннотирования getMessage() вам может потребоваться добавить другой метод сопоставления, как показано ниже.

 @Results(id = "messageQueryResult", value = {
  @Result(column = "ID", property = "id"),
  @Result(column = "NOTE", property = "note")
})
@Select("select ID, NOTE from vmessage where ID = #{id}")
MessageValue getById(@Param("id") Long id);
 

Эта результирующая карта имеет тот же идентификатор, поэтому вы можете удалить <resultMap /> ее из XML-карты, и она должна работать.

Комментарии:

1. большое вам спасибо, это работает на меня. Да cursorType означает SYS_REFCURSOR , что есть способ определить карту результатов как аннотации Java вместо XML?

2. @tine 🙏 Я пропустил ваш последний вопрос. Пожалуйста, ознакомьтесь с обновленным ответом.