3
votes

Spring batch JdbcCursorItemReader provoque un problème de mémoire insuffisante

J'utilise le framework Spring Batch pour effectuer une migration de données. Le lecteur que j'utilise est JdbcCursorItemReader. J'ai défini la taille de bloc à 500 et la taille de récupération du lecteur à 1000. Mais lorsque vous exécutez le service avec un lot de printemps, il semble juste lire toutes les données une fois dans la mémoire et manquer de mémoire. puis jeter un problème de mémoire pas assez. Voici comment je définis le lecteur:

   private JdbcCursorItemReader<Map<String, Object>> buildItemReader(final DataSource dataSource, String tableName,String tenant) {
        String tenantName = tenantHelper.determineTenant(tableName);
        JdbcCursorItemReader<Map<String, Object>> itemReader = new JdbcCursorItemReader<>();
        itemReader.setDataSource(dataSource);
        itemReader.setSql("select * from " + tableName + " where " + tenantName + " ='" + tenant + "'");
        itemReader.setRowMapper(new ColumnMapRowMapper());
        itemReader.setFetchSize(100);
        return itemReader;
    }

Quoi de plus, du document de lot de printemps ici , nous devrions être en mesure d'éviter le problème de mémoire en utilisant le jdbcCursorItemReader


5 commentaires

De toute évidence, la requête ne récupérera le résultat complet que parce que vous n'avez pas de limite de taille. Je pense que vous avez besoin de Partitioner


Salut @soorapadman, Le partitionneur veut-il diviser le processus en plusieurs étapes? Pour certaines raisons, je n'ai pas pu utiliser cette fonction car je dois créer une étape de manière dynamique. Je pense également à utiliser le jdbcPagingItemReader. Mais la pagination ne fonctionne pas non plus pour moi, j'ai également essayé comme décrit dans cette question: stackoverflow.com/questions/55369572/...


La taille de récupération n'est qu'un indice pour le pilote de base de données et son implémentation dépend du produit de base de données. Quelle base de données utilisez-vous?


J'utilise le postgresql. Et j'ai débogué le jdbcCursorItemReader, il a lu / écrit par la taille de récupération et la taille du morceau. Mais je ne sais pas pourquoi il utilise toute la mémoire et charge toutes les données dans la mémoire


ok merci pour la mise à jour. J'ai ajouté une réponse, j'espère que cela aide.


3 Réponses :


1
votes

Je ne sais pas pourquoi il utilise toute la mémoire et charge toutes les données dans la mémoire

Selon la documentation de Postgresql , le pilote collecte tous les résultats d'une requête à la fois.

Vous pouvez probablement essayer de désactiver le curseur en définissant la taille de récupération sur 0. Il existe d'autres contraintes comme expliqué dans le document susmentionné, veuillez vous assurer que votre code les respecte toutes. Juste pour référence, cela est similaire à ce qui pourrait arriver avec MySQL où la taille de récupération doit être définie sur Integer.MIN_VALUE pour diffuser les résultats (voir ici et ici ).

J'espère que cela vous aidera.


1 commentaires

Salut Ben, Merci pour votre réponse, vous avez raison de dire que le lecteur de curseur que j'ai utilisé va juste chercher tous les résultats à la fois qui constitueront un gros objet et entreront directement dans l'ancienne génération. C'est la cause première de mon problème. J'ai essayé de configurer la taille de récupération mais il s'avère que cela n'a pas fonctionné pour moi. Je résous enfin cela en utilisant le lecteur de pagination



4
votes

Vous pouvez essayer d'utiliser un JdbcPagingItemReader au lieu de JdbcCursorItemReader où la taille de la page peut être définie lors de sa configuration


2 commentaires

Merci d'avoir compris cela en utilisant le JdbcPagingItemReader


Veuillez fermer votre question en cliquant sur la coche à gauche de la réponse qui vous a le plus aidé



2
votes

J'ai compris cela en utilisant le jdbcPagingItemReader. La raison principale pour laquelle le lecteur de curseur consomme une mémoire massive est qu'il lit simplement toutes les données dans la mémoire, puis les traite, ce qui sera considéré comme un gros objet par la JVM et il sera alloué directement dans l'ancienne génération, jusqu'à ce que l'ensemble du processus terminé, il n'a pas pu être collecté.


0 commentaires