【SSH网上商城项目实战05】完成数据库的级联查询和分页

    xiaoxiao2021-03-25  147

    转自:http://blog.csdn.net/eson_15/article/details/51320212

    上一节我们完成了EasyUI菜单的实现。这一节我们主要来写一下CategoryServiceImpl实现类,完成数据库的级联查询。一般项目从后往前做,先做service(我们没有抽取Dao,最后再抽取),做完了再做上面层。

            在写之前,先看一下数据库中的表的情况:

    [sql] view plain copy print ? drop database if exists shop;  /*创建数据库,并设置编码*/  create database shop default character set utf8;    use shop;  /*删除管理员表*/  drop table if exists account;  /*删除商品类别表*/  drop table if exists category;    /*============================*/  /*      Table:管理员表结构                       */  /*============================*/  create table account  (      /* 管理员编号,自动增长 */      id int primary key not null auto_increment,      /* 管理员登录名 */      login varchar(20),      /* 管理员姓名 */      name varchar(20),      /* 管理员密码 */      pass varchar(20)  );    /*============================*/  /*     Table:商品类别表结构                      */  /*============================*/  create table category  (     /* 类别编号,自动增长 */     id  int primary key not null auto_increment,     /* 类别名称 */     type varchar(20),     /* 类别是否为热点类别,热点类别才有可能显示在首页*/     hot  bool default false,     /* 外键,此类别由哪位管理员管理 */     account_id int,     constraint aid_FK foreign key(account_id) references account(id)  );   drop database if exists shop; /*创建数据库,并设置编码*/ create database shop default character set utf8; use shop; /*删除管理员表*/ drop table if exists account; /*删除商品类别表*/ drop table if exists category; /*============================*/ /* Table:管理员表结构 */ /*============================*/ create table account ( /* 管理员编号,自动增长 */ id int primary key not null auto_increment, /* 管理员登录名 */ login varchar(20), /* 管理员姓名 */ name varchar(20), /* 管理员密码 */ pass varchar(20) ); /*============================*/ /* Table:商品类别表结构 */ /*============================*/ create table category ( /* 类别编号,自动增长 */ id int primary key not null auto_increment, /* 类别名称 */ type varchar(20), /* 类别是否为热点类别,热点类别才有可能显示在首页*/ hot bool default false, /* 外键,此类别由哪位管理员管理 */ account_id int, constraint aid_FK foreign key(account_id) references account(id) );        主要有两张表,商品类别表和管理员表,并且商品类别表中提供了一个外键关联管理员表。也就是商品和管理员是多对一的关系。现在我们开始编写查询商品的类别信息,需要级联管理员。

    1. 实现级联查询方法

            首先在CategoryService接口中定义该方法:

    [java] view plain copy print ? public interface CategoryService extends BaseService<Category> {      //查询类别信息,级联管理员      public List<Category> queryJoinAccount(String type); //使用类别的名称查询  }   public interface CategoryService extends BaseService<Category> { //查询类别信息,级联管理员 public List<Category> queryJoinAccount(String type); //使用类别的名称查询 }        然后我们在CategoryService的实现类CategoryServiceImpl中实现这个方法:

    [java] view plain copy print ? @Service("categoryService")  public class CategoryServiceImpl extends BaseServiceImpl<Category> implements CategoryService {        @Override      public List<Category> queryJoinAccount(String type) {          String hql = "from Category c where c.type like :type";          return getSession().createQuery(hql)                  .setString("type""%" + type + "%").list();      }  }   @Service("categoryService") public class CategoryServiceImpl extends BaseServiceImpl<Category> implements CategoryService { @Override public List<Category> queryJoinAccount(String type) { String hql = "from Category c where c.type like :type"; return getSession().createQuery(hql) .setString("type", "%" + type + "%").list(); } }        在两个Model中我们配一下关联注解:

    [java] view plain copy print ? //Category类中  @ManyToOne(fetch = FetchType.EAGER)  @JoinColumn(name = "account_id")  public Account getAccount() {      return this.account;  }  //Account类中  @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "account")  public Set<Category> getCategories() {      return this.categories;  }   //Category类中 @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "account_id") public Account getAccount() { return this.account; } //Account类中 @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "account") public Set<Category> getCategories() {     return this.categories; }         然后我们在测试类中测试一下:

    [java] view plain copy print ? @RunWith(SpringJUnit4ClassRunner.class)  @ContextConfiguration(locations="classpath:beans.xml")  public class CategoryServiceImplTest {        @Resource      private CategoryService categoryService;            @Test       public void testQueryJoinAccount() {          for(Category c : categoryService.queryJoinAccount("")) {               System.out.println(c);               System.out.println(c.getAccount());          }      }  }   @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations="classpath:beans.xml") public class CategoryServiceImplTest { @Resource private CategoryService categoryService; @Test public void testQueryJoinAccount() { for(Category c : categoryService.queryJoinAccount("")) { System.out.println(c); System.out.println(c.getAccount()); } } }

    2. 级联查询存在的问题

            我们看一下控制台的输出可以看出,它发了不止一条SQL语句,但是我们明明只查询了一次,为什么会发这么多语句呢?这就是常见的1+N问题。所谓的1+N问题,就是首先发出一条语句查询当前对象,然后发出N条语句查询关联对象,因此效率变得很低。这里就两个对象,如果有更多的对象,那效率就会大打折扣了,我们该如何解决这个问题呢?

            可能大家会想到将fetch设置生FetchType.LAZY就不会发多条语句了,但是这肯定不行,因为设置成LAZY后,我们就拿不到Account对象了,比较好的解决方法是我们自己写hql语句,使用join fetch。具体看修改后的CategoryServiceImpl实现类:

    [java] view plain copy print ? @Service("categoryService")  public class CategoryServiceImpl extends BaseServiceImpl<Category> implements CategoryService {        @Override      public List<Category> queryJoinAccount(String type) {          String hql = "from Category c left join fetch c.account where c.type like :type";          return getSession().createQuery(hql)                  .setString("type""%" + type + "%").list();      }  }   @Service("categoryService") public class CategoryServiceImpl extends BaseServiceImpl<Category> implements CategoryService { @Override public List<Category> queryJoinAccount(String type) { String hql = "from Category c left join fetch c.account where c.type like :type"; return getSession().createQuery(hql) .setString("type", "%" + type + "%").list(); } }        left join表示关联Account一起查询,fetch表示将Account对象加到Category中去,这样就只会发一条SQL语句了,并且返回的Category中也包含了Account对象了。

    3. 完成分页功能

            hibernate中的分页很简单,只需要调用两个方法setFirstResult和setMaxResults即可:我们修改一下CategoryService接口和它的实现类CategoryServiceImpl:

    [java] view plain copy print ? //CategoryService  public interface CategoryService extends BaseService<Category> {      //查询类别信息,级联管理员      public List<Category> queryJoinAccount(String type, int page, int size); //并实现分页  }    //CategoryServiceImpl  @Service("categoryService")  public class CategoryServiceImpl extends BaseServiceImpl<Category> implements CategoryService {        @Override      public List<Category> queryJoinAccount(String type, int page, int size) {          String hql = "from Category c left join fetch c.account where c.type like :type";          return getSession().createQuery(hql)                  .setString("type""%" + type + "%")                  .setFirstResult((page-1) * size) //从第几个开始显示                  .setMaxResults(size) //显示几个                  .list();      }  }   //CategoryService public interface CategoryService extends BaseService<Category> { //查询类别信息,级联管理员 public List<Category> queryJoinAccount(String type, int page, int size); //并实现分页 } //CategoryServiceImpl @Service("categoryService") public class CategoryServiceImpl extends BaseServiceImpl<Category> implements CategoryService {     @Override     public List<Category> queryJoinAccount(String type, int page, int size) {         String hql = "from Category c left join fetch c.account where c.type like :type";         return getSession().createQuery(hql)                 .setString("type", "%" + type + "%")                 .setFirstResult((page-1) * size) //从第几个开始显示                 .setMaxResults(size) //显示几个                 .list();     } }         我们在测试类中测试一下:

    [java] view plain copy print ? @RunWith(SpringJUnit4ClassRunner.class)  @ContextConfiguration(locations="classpath:beans.xml")  public class CategoryServiceImplTest {        @Resource      private CategoryService categoryService;        @Test      public void testQueryJoinAccount() {          for(Category c : categoryService.queryJoinAccount("",1,2)) { //显示第一页,每页2条数据              System.out.println(c + "," + c.getAccount());          }      }  }   @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations="classpath:beans.xml") public class CategoryServiceImplTest { @Resource private CategoryService categoryService; @Test public void testQueryJoinAccount() { for(Category c : categoryService.queryJoinAccount("",1,2)) { //显示第一页,每页2条数据 System.out.println(c + "," + c.getAccount()); } } }        为此,我们写完了Service的方法了,完成了对商品类别的级联查询和分页功能。

           相关阅读:http://blog.csdn.net/column/details/str2hiberspring.html

            整个项目的源码下载地址:http://blog.csdn.net/eson_15/article/details/51479994

    _____________________________________________________________________________________________________________________________________________________

    -----乐于分享,共同进步!

    -----更多文章请看:http://blog.csdn.net/eson_15

    顶 9 踩 1     上一篇【SSH网上商城项目实战04】EasyUI菜单的实现 下一篇【SSH网上商城项目实战06】基于DataGrid的数据显示

    我的同类文章

    ● 项目实战(29) ------【SSH网上商城】(29) http://blog.csdn.net •【SSH网上商城项目实战29】使用JsChart技术在后台显示商品销售报表2016-05-26阅读6456 •【SSH网上商城项目实战27】域名空间的申请和项目的部署及发布2016-05-23阅读14232 •【SSH网上商城项目实战26】完成订单支付后的短信发送功能2016-05-22阅读5114 •【SSH网上商城项目实战24】Struts2中如何处理多个Model请求2016-05-21阅读4585 •【SSH网上商城项目实战22】获取银行图标以及支付页面的显示2016-05-19阅读4141 •【SSH网上商城项目实战20】在线支付平台的介绍2016-05-18阅读4533 •【SSH网上商城项目实战28】使用Ajax技术局部更新商品数量和总价2016-05-24阅读5884 •【SSH网上商城项目实战30】项目总结(附源码下载地址)2016-05-27阅读25559 •【SSH网上商城项目实战25】使用java email给用户发送邮件2016-05-22阅读4381 •【SSH网上商城项目实战23】完成在线支付功能2016-05-20阅读9263 •【SSH网上商城项目实战21】从Demo中看易宝支付的流程2016-05-18阅读10166 更多文章
    转载请注明原文地址: https://ju.6miu.com/read-6358.html

    最新回复(0)