2017-09-25 12 views
0

Lors de la création de certains services, je rencontre des problèmes de performance, par exemple: pour appeler le service et obtenir une réponse (pour un objet Recette qui contient la liste des RecipeComponents - it a pris presque 2000ms), ce qui ressemble à ceci:objet qui contient la liste de certains éléments ne peut pas exposer les données de repos avec une seule requête

{ 
    "recipe_id": 55, 
    "recipeName": "Pizza", 
    "weight": 450, 
    "aproxPrice": 12, 
    "raiting": 7, 
    "caloriesCat": 1, 
    "foodCat": 2, 
    "calories": 300, 
    "user_id": 500, 
    "publishDate": 1505858400000, 
    "recipeComponents": [ 
     { 
      "component_id": 139, 
      "componentName": "veges", 
      "componentWeight": 100, 
      "componentDescription": "Some desc", 
      "componentCalories": 200 
     }, 
     { 
      "component_id": 140, 
      "componentName": "rice", 
      "componentWeight": 100, 
      "componentDescription": "some stuff", 
      "componentCalories": 350 
     }, 
     { 
      "component_id": 141, 
      "componentName": "tomato", 
      "componentWeight": 100, 
      "componentDescription": "XXXXXXX", 
      "componentCalories": 150 
     }, 
     { 
      "component_id": 142, 
      "componentName": "souce", 
      "componentWeight": 100, 
      "componentDescription": "xxsdsds", 
      "componentCalories": 250 
     } 
    ] 
} 

pour plus de 70 recettes (avec des composants) pour obtenir la réponse qu'il faut 10000ms autour

la raison est la méthode de service, appelez en fait la base de données 2 fois (au débutant je n'ai pas réalisé son assez lent):

dans le niveau de dépôt j'ai deux classes: RecipeRowMapper et RecipeComponentRowMapper pour mapper des données qui fonctionne bien pour les requêtes simples comme vous pouvez le voir ci-dessus. J'ai donc décidé d'utiliser ResultSetExtractor dans le niveau du référentiel, où sera une requête unique avec une jointure à gauche/une jointure interne.

@Override 
public List<Recipe> getAllRecipesWithSingleQuery() { 

    List<Recipe> recipes = jdbcTemplate.query(SqlRecipeStaticData.sGetAllRecipesWithSingleQuery, 
      new ResultSetExtractor<List<Recipe>>() { 

       public RecipeComponentRowMapper componentRowMapper = new RecipeComponentRowMapper(); 

       public RecipeRowMapper recipeRowMapper = new RecipeRowMapper(); 

       @Override 
       public List<Recipe> extractData(ResultSet rs) throws SQLException, DataAccessException { 
        List<Recipe> recipes = new ArrayList<>(); 
        Integer recipeId = null; 
        Recipe currentRecipe = null; 
        int recipeIdx = 0; 
        int componentIdx = 0; 
        while (rs.next()) { 
         if (currentRecipe == null || !recipeId.equals(rs.getInt("recipe_id"))) { 
          recipeId = rs.getInt("recipe_id"); 
          currentRecipe = new Recipe(); 

          currentRecipe = recipeRowMapper.mapRow(rs, recipeIdx++); 
          List<RecipeComponent> components = currentRecipe.getRecipeComponents(); 
          if (components == null) { 
           components = new ArrayList<>(); 

           RecipeComponent component = componentRowMapper.mapRow(rs, componentIdx++); 

           components.add(component); 

          } 

          currentRecipe.setRecipeComponents(components); 
          recipes.add(currentRecipe); 

         } 

        } 
        return recipes; 
       } 

      }); 
    return recipes; 
} 

et dans ce cas j'obtenir une réponse (pour 70 recettes) dans quelque chose autour de 1000ms, mais le problème est la réponse est incomplète (ne marche pas avoir la liste complète des recipeComponents, mais seulement le premier composant sur la liste):

[ 
    { 
     "recipe_id":55, 
     "recipeName":"Pizza", 
     "weight":450, 
     "aproxPrice":12, 
     "raiting":7, 
     "caloriesCat":1, 
     "foodCat":2, 
     "calories":300, 
     "user_id":500, 
     "publishDate":1505858400000, 
     "recipeComponents":[ 
     { 
      "component_id":139, 
      "componentName":"veges", 
      "componentWeight":100, 
      "componentDescription":"Some desc", 
      "componentCalories":200 
     } 
     ] 
    } 
] 

** ma requête fonctionne correctement.

select recipe_id,recipe_name,recipe_weight,recipe_aprox_price,recipe_raiting,recipe_calories,recipe_user_id,recipe_kcategory_id,recipe_fcategory_id,recipe_published_date,comp_id, comp_name,comp_weight,comp_description,comp_calories,comp_recipe_id from public.recipe_store INNER JOIN public.recipe_components ON (public.recipe_store.recipe_id=public.recipe_components.comp_recipe_id) 

Je trouve aussi ici quelques idées pour passer à ORM pour résoudre ce problème, mais si vous avez des idées, d'autres solutions pour résoudre ce problms je serai reconnaissant.

Répondre

0

D'accord, je résolu ce problème, voici asnwer comment il doit être écrit:

@Override 
    public List<Recipe> getAllRecipesWithSingleQuery() { 
     final Map<Integer,Recipe> recipesAll = new HashMap<>(); 
     this.jdbcTemplate.query(SqlRecipeStaticData.sGetAllRecipesWithSingleQuery, new RowMapper<RecipeComponent>(){ 

      @Override 
      public RecipeComponent mapRow(ResultSet rs, int rowNum) throws SQLException { 
       Integer recipeId = rs.getInt("r_id"); 
       Recipe recipe = recipesAll.get(recipeId); 
       if(recipe==null){ 
        recipe = new Recipe(); 
        recipe.setRecipe_id(recipeId); 
        recipe.setRecipeName(rs.getString("recipe_name")); 
        recipe.setAproxPrice(rs.getDouble("recipe_aprox_price")); 
        recipe.setWeight(rs.getDouble("recipe_weight")); 
        recipe.setRaiting(rs.getInt("recipe_raiting")); 
        recipe.setCalories(rs.getDouble("recipe_calories")); 
        recipe.setUser_id(rs.getInt("ruser_id")); 
        recipe.setCaloriesCat(rs.getInt("kcategory_id")); 
        recipe.setFoodCat(rs.getInt("fcategory_id")); 
        recipe.setPublishDate(rs.getDate("published_date")); 
        recipe.setRecipeComponents(new ArrayList<>()); 
        recipesAll.put(recipeId, recipe); 
       } 
       RecipeComponent component = new RecipeComponent(); 
       component.setComponent_id(rs.getInt("id")); 
       component.setComponentName(rs.getString("name")); 
       component.setComponentWeight(rs.getDouble("weight")); 
       component.setComponentDescription(rs.getString("description")); 
       component.setRecipe_id(recipeId); 
       component.setComponentCalories(rs.getDouble("calories")); 
       recipe.getRecipeComponents().add(component); 

       return component; 

      } 


     }); 
     List<Recipe> result = new ArrayList<Recipe>(recipesAll.values()); 
     return result; 


    } 

J'espère qu'un jour cela aide quelqu'un :)