2010-01-19 7 views
6

Próbuję przejrzeć każdy wiersz tabeli w MySQL przy użyciu Spring i JdbcTemplate. Jeśli się nie mylę to powinno być tak proste, jak:Jak zarządzać dużym zestawem danych przy użyciu Spring MySQL i RowCallbackHandler

JdbcTemplate template = new JdbcTemplate(datasource); 
template.setFetchSize(1); 
// template.setFetchSize(Integer.MIN_VALUE) does not work either    
template.query("SELECT * FROM cdr", new RowCallbackHandler() { 
    public void processRow(ResultSet rs) throws SQLException { 
    System.out.println(rs.getString("src")); 
    } 
}); 

dostaję OutOfMemoryError ponieważ stara się przeczytać całość. Jakieś pomysły?

+0

Hej, opieka zmienić przyjętą odpowiedź. Twoje pytanie dotyczyło wiosny, a odpowiedź @ scompt.com jest bardziej odpowiednia. Dzięki wielkie. – Gray

Odpowiedz

9

Statement#setFetchSize()javadoc już stwierdza:

Daje sterownika JDBC do podpowiedź co do liczby wierszy, które powinny być pobrane z bazy danych

Sterownik może faktycznie zastosować lub zignorować podpowiedź. Niektóre sterowniki ignorują to, niektóre sterowniki stosują je bezpośrednio, niektóre sterowniki wymagają większej liczby parametrów. Sterownik JDBC MySQL należy do ostatniej kategorii. Jeśli zaznaczysz MySQL JDBC driver documentation, zobaczysz następujące informacje (przewinąć w dół aż o 2/3 nagłówka ResultSet):

Aby włączyć tę funkcję, należy utworzyć instancję oświadczenie, w następujących sposób:

stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY); 
stmt.setFetchSize(Integer.MIN_VALUE); 

Proszę przeczytać całą sekcji dokumentu, opisuje ograniczeniach tego podejścia, jak również.

Aby uruchomić go na wiosnę, trzeba jednak przedłużyć/zastąpić JdbcTemplate niestandardową implementacją. Ponieważ nie robię wiosny, nie mogę szczegółowo opisać tego, ale teraz przynajmniej wiesz, gdzie szukać.

Powodzenia.

+2

Dodałem rozwiązanie oparte na wiosennej tutaj: http://stackoverflow.com/questions/2095490/how-to-manage-a-large-dataset-using-spring- mysql-and-rowcallbackhandler/2834590 # 2834590 –

0

Jeśli podejrzewasz, że pojawia się błąd OutOfMemory z powodu odczytu całej tabeli, dlaczego nie możesz spróbować podzielić zapytania. Użyj filtrów, klauzula LIMIT itp

+1

To spowodowałoby, że logika procesu byłaby znacznie bardziej złożona. Obecnie testuję sposób, aby faktycznie strumieniować za pośrednictwem Spring JdbcTeamplate. Dowiesz się, czy to działa ... – rmarimon

18

Oto rozwiązanie sprężynowe oparte na answer dostarczone przez BalusC.

class StreamingStatementCreator implements PreparedStatementCreator { 
    private final String sql; 

    public StreamingStatementCreator(String sql) { 
     this.sql = sql; 
    } 

    @Override 
    public PreparedStatement createPreparedStatement(Connection connection) throws SQLException { 
     final PreparedStatement statement = connection.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); 
     statement.setFetchSize(Integer.MIN_VALUE); 
     return statement; 
    } 
} 

Gdzieś w kodzie:

DataSource dataSource = ...; 
RowCallbackHandler rowHandler = ...; 
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); 
jdbcTemplate.query(new StreamingStatementCreator("SELECT * FROM huge_table"), rowHandler); 
+1

warto zauważyć, że musisz się upewnić, że właściwość useServerPrepStmts w twoim łańcuchu połączenia jest ustawiona poprawnie, tzn. jeśli przypadkiem ten zbiór na false ^^ nie zadziała i zapisze w nim pełny wynik set –

+0

Warto zauważyć, że za pomocą Spring 3 setFetchSize JdbcTemplate ignoruje limity mniejsze niż 1 i dlatego MUSISZ przesłonić bardzo podstawową funkcję. Fuj. –

+0

@AndrewGilmartin Po 4.3, powinien działać - Uwaga: od 4.3, wartości ujemne inne niż -1 zostaną przekazane do sterownika, ponieważ np. MySQL obsługuje specjalne zachowanie dla Integer.MIN_VALUE. – Hlex

Powiązane problemy