Tous les HowTo

Utilisation de curseurs avec groovy et mysql

Un exemple de code groovy très simple : on veut faire un traitement sur tous les objets d'une table mysql.  Petit détail : la table contient près de 10 Milions de lignes.

#!/usr/bin/env groovy
import groovy.sql.Sql
def sql = Sql.newInstance("jdbc:mysql://localhost:3306/webremix", "xxxx", "yyyy", "com.mysql.jdbc.Driver")

String statement1 = 'select * from Article'
sql.eachRow(statement1, {
    article -> // do some processing
})

Si on lance le script tel quel, on a rapidement une erreur :

 ./test.groovy Caught: java.lang.OutOfMemoryError: Java heap space at test.run(test.groovy:9) 

 

Au lieu de lire les données au fur et a mesure depuis la base, le script a tenté de charger en mémoire les 10 milions de lignes = un peu trop gros à digérer.

Le problème ne vient pas de groovy, qui utilise bien un iterateur, mais de la définition de la connection jdbc à mysql.  En effet la documentation du connecteur jdbc de mysql spécifie que par defaut avec MySQL > 5.0.2 la valeur useCursorFetch est à false et que donc mysql n'utilise pas de curseur coté serveur pour envoyer les données au client.

Si l'on veut que mysql utilise bien un curseur coté serveur, il faut modifier l'URL de connection jdbc et ajouter les paramètres suivants :

  • useServerPrepStmts=true
  • useCursorFetch=true
  • defaultFetchSize=100 (ou tout autre valeur "raisonnable" > 0)

Notre code modifié devient alors :

 #!/usr/bin/env groovy import groovy.sql.Sql def sql = Sql.newInstance("jdbc:mysql://localhost:3306/webremix?useServerPrepStmts=true&useCursorFetch=true&defaultFetchSize=100", "xxxx", "yyyy", "com.mysql.jdbc.Driver") String statement1 = 'select * from Article' sql.eachRow(statement1, { article -> // do some processing }) 

 

Et il s'execute alors sans erreur de type "OutOfMemoryError"

 

  • Clip to Evernote