2016-07-28 21 views
3

Hier ist der Code. Nehmen wir an, es gibt viele große Bilder in der db, so dass ich nur einen im Speicher behalten möchte. Wie schreibt man das mit JDK 8 Features wie Lambda und Streams?Wie JDBCTemplate Abfrage mit JDK8 Features neu schreiben?

Ich fing an, diese zu verwenden, aber es scheiterte (von https://spring.io/guides/gs/relational-data-access/ und www.jooq.org/java-8-and-sql) und die Verwendung von ResultSetExtractor funktioniert als intendent, aber gibt es eine Möglichkeit, es ohne ResultSetExtractor zu tun?

jdbcTemplate.query( 
      "select id,image,mimetype from images", 
      new ResultSetExtractor(){ 
       @Override 
       public List extractData(ResultSet rs) throws SQLException, DataAccessException { 
         while(rs.next()){ 
          createThumbnail(new ImageHolder(rs.getInt("id"), rs.getBytes("image"), rs.getString("mimetype"))); 
         } 
         return null; 
        } 
      } 
    ); 

Das ist gut aussehende stream/Lambda-Version, die funktioniert, aber hält zu viele Dinge im Speicher und gibt OOME früher oder später.

jdbcTemplate.query( 
      "select id,image,mimetype from images", 
      (rs,rowNum)->new ImageHolder(rs.getInt("id"), rs.getBytes("image"),rs.getString("mimetype")) 
    ).stream().forEach( 
        imageHolder -> createThumbnail(imageHolder) 
    )); 

Dies lädt einfach alle Zeilen, bevor es beginnt, um sie „Streaming“.

Antwort

2

Eine Lösung könnte darin bestehen, die Erzeugung des Miniaturbildes im ersten Lambda zu verschieben, was direkt zu Ihrem ersten Beispiel führt.

jdbcTemplate.query( 
     "select id,image,mimetype from images", 
     (rs,rowNum)-> { 
      createThumbnail(new ImageHolder(
       rs.getInt("id"), 
       rs.getBytes("image"), 
       rs.getString("mimetype"))); 
     }) 
) 

Um eine Struktur ähnlich dem haben Sie die Abfragemethode zu erreichen versucht, sollte einen Strom zurückkehren, so dass Sie vor dem Streaming nicht alles sammeln müssen.

+0

Ja, gute Lösung, um dieses verpasst. Ich werde testen, ob es tatsächlich funktioniert;) Irgendwie habe ich geglaubt, dass die Abfrage Stream (fähige) Sache zurückgibt, aber obvisouly ist es nicht. – ljack

+0

ops, 'Verursacht von: org.postgresql.util.PSQLException: Nicht genügend Arbeitsspeicher beim Abrufen von Abfrageergebnissen. ' – ljack

1

Sie könnten Ihre JDBC Statement.setFetchSize() auf etwas vernünftigeres als den Standard (see also some hints here) begrenzen.

Eine Alternative ist manuell Paginieren wie folgt:

int size = 10; 
jdbcTemplate.query(

    // This query creates chunks of 10 and shows the low/high id value in each chunk 
    "select id1, id2 " 
    + "from (" 
    + " select " 
    + " id AS id1, " 
    + " lead(id, ?) over (order by id) AS id2, " 
    + " row_number() over (order by id) rn from images) i " 
    + " from images " 
    + ") i  
    + "where rn % ? = 0", 
    new Object[] { size, size }, 
    rs1 -> { 
     while (rs1.next()) 
      jdbcTemplate.query(
       // This query fetches only images for each chunk 
       "select id, image, mimetype from images " 
       + "where id >= ? and id < coalesce(?, 2147483647)", 
       new Object[] { rs1.getInt(1), rs1.getInt(2) }, 
       rs2 -> { 
        createThumbnail(new ImageHolder(
         rs2.getInt("id"), 
         rs2.getBytes("image"), 
         rs2.getString("mimetype") 
        )); 
        return null; 
       } 
      ); 

     return null; 
    } 
);