jfinal如何避免n+1

jkluooop 发布于 2015/04/29 17:20
阅读 291
收藏 0

@JFinal 你好,想跟你请教个问题:

      我在使用jfinal返回到客户端json数据的时候,想如何避免N+1次查询。
  比如显示一个帖子列表的时候,需要返回给客户端  { [ { "blog_id":1,"title","xxxx","user":{}},{ "blog_id":1,"title","xxxx","user":{}}]}
  如果用 blog left join user,那么生成json的时候,得用Map重新构造一下查找出来的List<Record>
  如果不用left join, 那就是得先查找出List<Blog>,然后遍历的时候,再发一条sql,用blog.put("user",user);来实现,
  用哪种方案好呢?场景是移动服务端。
  或者有别的方案更合适,那也很好。

  

加载中
0
JFinal
JFinal

    直接 sql 解决即可:

String sql = "select b.*, u.id, u.name from blog b join user u on b.userId = u.id limit 1, 10";
List<Blog> blogList = Blog.me.find(sql);
renderJson(blogList);

    由于每个 Blog 必定与一个 User 关联,所以无所谓 left join 和 inner join 了,必定会关联得上。注意上面的 select 块中示范了最可能用到的 u.id、u.name,这里按需求来做。

     这个方案对于多个 blog 对应同一个 user 会有一定的数据冗余,但如果 user 表中需要的数据很少,例如只有 id和name的话可以忽略其影响,如果冗余非常之大,可以采用下面的方式:

1: sql 查出需要的 blogList

2:从 blogList 得到所对应的用户 id 集合,然后通过 select ... from user where id in(id集合)得到 blogList 所对应的 userList

3:对 blogList 进行循环,将 userList 中相对应的数据使用 blog.put("user", user) 放进去

3:renderJson(blogList);

   这个方案只需要执行两条 sql,而不是 N + 1 条 sql。这个方案还可以让上面的第三步在客户端进行,而服务端只需要将 blogList、userList 的 json 数据同时发过去即可。

jkluooop
jkluooop
谢谢波总的指点。虽然方案1查出来还是不满足需求,因为没有嵌套结构,客户端跟服务端的数据格式是固定的。 但那个1+1的很不错,采纳,之前我太钻牛角了。 再次感谢, PS: Jfinal很好用, 如果有时间,想把Jfinal的mvc抽出来,配合底层mina,做一个长连接的框架。
0
jkluooop
jkluooop
补充一下,如果采取2条sql的形式,在第3步,blog.put("user", user) 的时候,
注意确认下select ... from user where id in(id集合)得到 blogList 所对应的 userList ,
这里的userList会不会跟blogList按 i 的顺序一一对应,要不然那就得进行 N*N轮判断去匹配了。而不是N轮设值
0
jkluooop
jkluooop

额,实验了下。
在 findBlogById(blogid)下,用map重构效率更高。

String sql = "select b.*, u.uid, u.name from blog b join user u on b.createBy = u.uid limit 1, 10";
List<Blog> blogList = Blog.me.find(sql);
for(Blog blog: blogList){
	HashMap<String,Object> user=new HashMap<String,Object>();
	user.put("uid", blog.get("uid"));
	user.put("name", blog.get("name"));
	blog.remove("uid");
	blog.remove("name");
	blog.put("user", user);
}
renderJson(blogList);
在 findblogsOfUser(uid)情况下, 先查user,再查 blogs, 再user.put("blogs",blogs).  2次sql.
返回顶部
顶部