0

在创建一些服务期间,我遇到了一些性能问题,例如:调用服务并获得响应(对于一个包含 RecipeComponents 列表的对象 Recipe - 它花费了将近 2000 毫秒),如下所示:

{
    "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
        }
    ]
}

对于 70 多个食谱(带有组件)来获得响应大约需要 10000 毫秒

原因是服务方法,实际上调用数据库 2 次(一开始我没有意识到它很慢):

@Override
public List<Recipe> getAllRecipes() {
    List<Recipe> recipes = recipeRepository.getAllRecipes(); <- first time to get all recipes
    for (Recipe recipe : recipes) {
        List<RecipeComponent> components = recipeComponentRepository
                .findAllComponentsAssignedToRecipe(recipe.getRecipe_id()); <- 2nd time to get components assigned to recipe.
        recipe.setRecipeComponents(components);
    }
    return recipes;

在存储库层中,我有两个类:RecipeRowMapper 和 RecipeComponentRowMapper 来映射数据——正如您在上面看到的,这对于单个查询非常有效。

所以我决定在存储库层使用 ResultSetExtractor,其中将是带有左连接/内连接语句的单个查询。

@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;
}

在这种情况下,我在 1000 毫秒左右得到响应(对于 70 个食谱),但问题是响应不完整(没有完整的食谱组件列表,但只有列表中的第一个组件):

[  
   {  
      "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
         }
      ]
   }
]

**我的查询工作正常。

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)

我在这里也找到了一些想法来切换到 ORM 来解决这个问题,但是如果你有一些想法,解决这个问题的其他解决方案我将不胜感激。

4

1 回答 1

0

好吧,我解决了这个问题,下面是它应该如何写:

@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;


    }

我希望有一天这可以帮助某人:)

于 2017-09-26T17:43:08.363 回答