Как реализовать 2 набора результатов из MyBatis

#java #spring-boot #mybatis

Вопрос:

Я работаю над приложением springboot, в котором mybatis вызывает хранимую процедуру DB2, и эта хранимая процедура возвращает 2 набора результатов: и для каждого набора результатов я определил модель(Fruit.java и Animal.java)

набор результатов #1

ID Имя кол-во
1 Apple 2
2 Оранжевый 3
3 банан 5

набор результатов #2

Тип номер ЛОК
обезьяна 2000 Лондон
собака 3000 НЬЮ-ЙОРК
кошка 8000 LA

в MyMapper.java, каким должен быть мой тип результата?

Я пытался:

 @Select(Value = "{call ....}) 
@Options(StatementType =    StatementType.CALLABLE) 
@Results({   
  @Result(property="id",  column="ID",    
  @Result(property="name", column="NAME",      
  @Result(property="qty", column="QTY" })
List<Fruit> getFruits(Map<String, String> params); 

@Select(Value = "{call ....})
@Options(StatementType = StatementType.CALLABLE)
@Results({
  @Result(property="type", column="TYPE", 
  @Result(property="num", column="NUM", 
  @Result(property="loc", column="LOC"
})
List<Animal> getAnimals(Map<String, String> params); 
 

что не сработало, я получил результирующий набор #1 таким образом, но не получил результирующий набор #2 (все поля из результирующего набора#2 вернулись пустыми) .

Я тоже пытался:

  @Select(Value = "{call ....})
 @Options(StatementType = StatementType.CALLABLE)
 List<?> getResultSets(Map<String, String> params); 
 

и:

   @Select(Value = "{call ....})
  @Options(StatementType = StatementType.CALLABLE)
  List<List<?>> getResultSets(Map<String, String> params); 
 

Для обоих я получил «java.lang.Исключение UnsupportedOperationException»:

 Caused by: java.lang.UnsupportedOperationException
    at org.apache.ibatis.reflection.wrapper.CollectionWrapper.findProperty(CollectionWrapper.java:42)
    at org.apache.ibatis.reflection.MetaObject.findProperty(MetaObject.java:76)
    at org.apache.ibatis.executor.resultset.FastResultSetHandler.applyAutomaticMappings(FastResultSetHandler.java:342)
    at org.apache.ibatis.executor.resultset.FastResultSetHandler.getRowValue(FastResultSetHandler.java:267)
    at org.apache.ibatis.executor.resultset.FastResultSetHandler.handleRowValues(FastResultSetHandler.java:216)
    at org.apache.ibatis.executor.resultset.FastResultSetHandler.handleResultSet(FastResultSetHandler.java:188)
    at org.apache.ibatis.executor.resultset.FastResultSetHandler.handleResultSets(FastResultSetHandler.java:154)
    at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:57)
    at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:70)
    at org.apache.ibatis.executor.ReuseExecutor.doQuery(ReuseExecutor.java:54)
    at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:259)
    at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:132)
    at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:105)
    at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:81)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:104)
 

Google говорит, что это потому, что я должен использовать конкретный тип вместо дженериков.
Но результирующие наборы бывают разных типов: Список фруктов и Список животных , что мне делать?

Я использую все аннотации и не использую xml для mybatis. в pom.xml Я использую mybatis-spring-boot-starter, если это поможет.

Я застрял на этом навсегда. Спасибо.

Ответ №1:

Я проверил это с помощью следующей процедуры.
Она принимает два параметра и возвращает результаты fruit сначала, затем animal .
Дайте мне знать, если вам нужно, чтобы я внес некоторые коррективы.

 create or replace procedure test_proc (
  in p1 varchar(20),
  in p2 varchar(20)
)
dynamic result sets 2
begin
  declare c1 cursor with return to caller for
  select * from animal;
  declare c2 cursor with return to caller for
  select * from fruit;
  open c2;
  open c1;
end
 

Метод Java-картографа будет выглядеть следующим образом.
Поскольку вы получаете два набора результатов, вам необходимо указать две карты результатов в @ResultMap .
Обратите внимание, что порядок имеет значение.

 @Select("{call test_proc(#{p1,mode=IN,jdbcType=VARCHAR},#{p2,mode=IN,jdbcType=VARCHAR})}")
@Options(statementType = StatementType.CALLABLE)
@ResultMap("fruitResultMap,animalResultMap")
List<List<?>> execProc(Map<String, String> params);
 

Возвращаемый список содержит два списка. Первый есть List<Fruit> , а второй есть List<Animal> .

Теперь, чтобы определить эти карты результатов без XML-картографа, вам нужно объявить дополнительные методы.

 @Results(id = "fruitResultMap", value = {
  @Result(property = "id", column = "ID"),
  @Result(property = "name", column = "NAME"),
  @Result(property = "qty", column = "QTY")
})
@Select("select * from fruit")
List<Fruit> getFruits();

@Results(id = "animalResultMap", value = {
  @Result(property = "type", column = "TYPE"),
  @Result(property = "num", column = "NUM"),
  @Result(property = "loc", column = "LOC")
})
@Select("select * from animal")
List<Animal> getAnimals();
 

А вот исполняемый демо-проект:
https://github.com/harawata/mybatis-issues/tree/master/so-69145531

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

1. Большое вам спасибо !!! Ты просто спасатель! в моей ситуации я заменил имена таблиц именами курсоров, и Вуаля, я получил два набора результатов.