ibatis-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Giovanni Cuccu (JIRA)" <ibatis-...@incubator.apache.org>
Subject [jira] Commented: (IBATIS-466) Incorrect behaviour when combining RowHandler with groupBy
Date Fri, 17 Apr 2009 09:23:15 GMT

    [ https://issues.apache.org/jira/browse/IBATIS-466?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12700095#action_12700095
] 

Giovanni Cuccu commented on IBATIS-466:
---------------------------------------

I was using the two features together. My problem was the following.
I have a query mapped with a resultmap with three levels A has a list of B and B has a list
of C.
The query returns a lot fo rows that are serialized to xml. 
the resulting xml is the soapbody of a webservice response.
when the query returns a lot of rows the memory usage goes very high and the OutOfMemory errors
arise.
I ended in implementing a sort of streaming webservice where the response is pushed (via servlet
response) to the client as the rows came form the db.
I need the two feature together because the broup by is needed to return the correct xml structure
and the rowhandler is used in order to reduce memory usage.
An implementation or an hint that allows me to use the group by and the row handler assuming
that i'm responsible for the order of the row would be very nice.


> Incorrect behaviour when combining RowHandler with groupBy
> ----------------------------------------------------------
>
>                 Key: IBATIS-466
>                 URL: https://issues.apache.org/jira/browse/IBATIS-466
>             Project: iBatis for Java
>          Issue Type: Bug
>          Components: SQL Maps
>    Affects Versions: 2.3.0
>            Reporter: William Shields
>
> Assuming:
> CREATE TABLE Person {
>   person_id NUMBER PRIMARY KEY,
>   name VARCHAR2(100)
> )
> CREATE TABLE Album (
>   album_id NUMBER PRIMARY KEY,
>   owner NUMBER REFERENCES (Person.person_id),
>   name VARCHAR2(100)
> )
> and
> public class Person {
>   private long personId;
>   private String name;
>   private List<Album> albums;
>   ...
> }
> public class Album {
>   private long albumId;
>   private long owner;
>   private String name;
>   ...
> }
> with query:
> <resultMap id="album" class="Abum">
>   <result property="albumId" column="ALBUM_ID"/>
>   <result property="owner" column="PERSON_ID"/>
>   <result property="name" column="ALBUM_NAME"/>
> </resultMap>
> <resultMap id="person" class="Person" groupBy="personId">
>   <result property="personId" column="PERSON_ID"/>
>   <result property="name" column="PERSON_NAME"/>
>   <result property="albums" resultMap="album"/>
> </resultMap>
> <select id="selectAlbums" resultMap="person">
>   SELECT person_id, p.name person_name, album_id, a.name album_name
>   FROM Person p, Album a
>   WHERE person_id = owner
> </select>
> with data:
> Person:
> 1 John
> 2 Mary
> Album:
> 10 1 "Bat Out Of Hell"
> 11 2 "The Wall"
> 12 2 "Eyes Open"
> 12 2 "White Ladder"
> Now, queryForList() works correctly.  Two Person objects are returned.  The first (John)
has 1 album, Mary has 3.  If instead you do:
> queryWithRowHandler("....selectAlbums", new RowHandler() {
>   public void handleRow(Object valueObject) {
>     Person p = (Person)valueObject;
>     System.out.println(p.getName() + " has " + p.getAlbums().size() + " albums");
>   }
> }
> It displays 1 for each of the two rows.  The RowHandler is being called on the first
row and then it continues to add to the sub-list.  This is a real problem if you want to process
the fully loaded value object.  I've come up with this workaround:
> public interface TypedRowHandler<T> {
>   void handle(T t);
> }
> public class CleverRowHandler<T> implements RowHandler {
>   TypedRowHandler<T> handler;
>   private T last;
>   public CleverRowHandler(TypedRowHandler<T> handler) {
>     this.handler = handler;
>   }
>   public void handleRow(Object valueObject) {
>     flush();
>     last = (T)valueObject;
>   }
>   public void flush() {
>     if (last != null) {
>       handler.handler(last);
>     }
>     last = null;
>   }
> }
> with DAO code:
> public void processPersons() {
>   CleverRowHandler<Person> rh = new CleverRowHandler<T>(new TypedRowHandler<Person>()
{
>     public void handle(Person p) {
>       // do whatever
>     }
>   };
>   try {
>     getSqlMapClientTemplate().queryWithRowHandler("....selectPersons", rh);
>   } finally {
>     rh.flush();
>   }
> }
> but that's rather messy.  I believe that the current behaviour is a bug and introduces
potential threading issues (in my case my row handler creates a Runnable and submits it to
a ExecutorService, which is a problem if ibatis is still adding objects to the sub-list).

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


Mime
View raw message