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

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

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

  1. drop database if exists shop;  
  2. /*创建数据库,并设置编码*/  
  3. create database shop default character set utf8;  
  4.   
  5. use shop;  
  6. /*删除管理员表*/  
  7. drop table if exists account;  
  8. /*删除商品类别表*/  
  9. drop table if exists category;  
  10.   
  11. /*============================*/  
  12. /*      Table:管理员表结构                       */  
  13. /*============================*/  
  14. create table account  
  15. (  
  16.     /* 管理员编号,自动增长 */  
  17.     id int primary key not null auto_increment,  
  18.     /* 管理员登录名 */  
  19.     login varchar(20),  
  20.     /* 管理员姓名 */  
  21.     name varchar(20),  
  22.     /* 管理员密码 */  
  23.     pass varchar(20)  
  24. );  
  25.   
  26. /*============================*/  
  27. /*     Table:商品类别表结构                      */  
  28. /*============================*/  
  29. create table category  
  30. (  
  31.    /* 类别编号,自动增长 */  
  32.    id  int primary key not null auto_increment,  
  33.    /* 类别名称 */  
  34.    type varchar(20),  
  35.    /* 类别是否为热点类别,热点类别才有可能显示在首页*/  
  36.    hot  bool default false,  
  37.    /* 外键,此类别由哪位管理员管理 */  
  38.    account_id int,  
  39.    constraint aid_FK foreign key(account_id) references account(id)  
  40. );  
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接口中定义该方法:

  1. public interface CategoryService extends BaseService<Category> {  
  2.     //查询类别信息,级联管理员  
  3.     public List<Category> queryJoinAccount(String type); //使用类别的名称查询  
  4. }  
public interface CategoryService extends BaseService<Category> {
    //查询类别信息,级联管理员
    public List<Category> queryJoinAccount(String type); //使用类别的名称查询
}
        然后我们在CategoryService的实现类CategoryServiceImpl中实现这个方法:

  1. @Service(“categoryService”)  
  2. public class CategoryServiceImpl extends BaseServiceImpl<Category> implements CategoryService {  
  3.   
  4.     @Override  
  5.     public List<Category> queryJoinAccount(String type) {  
  6.         String hql = ”from Category c where c.type like :type”;  
  7.         return getSession().createQuery(hql)  
  8.                 .setString(”type”“%” + type + “%”).list();  
  9.     }  
  10. }  
@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中我们配一下关联注解:

  1. //Category类中  
  2. @ManyToOne(fetch = FetchType.EAGER)  
  3. @JoinColumn(name = “account_id”)  
  4. public Account getAccount() {  
  5.     return this.account;  
  6. }  
  7. //Account类中  
  8. @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = “account”)  
  9. public Set<Category> getCategories() {  
  10.     return this.categories;  
  11. }  
//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;
}
        然后我们在测试类中测试一下:

  1. @RunWith(SpringJUnit4ClassRunner.class)  
  2. @ContextConfiguration(locations=“classpath:beans.xml”)  
  3. public class CategoryServiceImplTest {  
  4.   
  5.     @Resource  
  6.     private CategoryService categoryService;  
  7.       
  8.     @Test  
  9.      public void testQueryJoinAccount() {  
  10.         for(Category c : categoryService.queryJoinAccount(“”)) {  
  11.              System.out.println(c);  
  12.              System.out.println(c.getAccount());  
  13.         }  
  14.     }  
  15. }  
@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实现类:

  1. @Service(“categoryService”)  
  2. public class CategoryServiceImpl extends BaseServiceImpl<Category> implements CategoryService {  
  3.   
  4.     @Override  
  5.     public List<Category> queryJoinAccount(String type) {  
  6.         String hql = ”from Category c left join fetch c.account where c.type like :type”;  
  7.         return getSession().createQuery(hql)  
  8.                 .setString(”type”“%” + type + “%”).list();  
  9.     }  
  10. }  
@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:

  1. //CategoryService  
  2. public interface CategoryService extends BaseService<Category> {  
  3.     //查询类别信息,级联管理员  
  4.     public List<Category> queryJoinAccount(String type, int page, int size); //并实现分页  
  5. }  
  6.   
  7. //CategoryServiceImpl  
  8. @Service(“categoryService”)  
  9. public class CategoryServiceImpl extends BaseServiceImpl<Category> implements CategoryService {  
  10.   
  11.     @Override  
  12.     public List<Category> queryJoinAccount(String type, int page, int size) {  
  13.         String hql = ”from Category c left join fetch c.account where c.type like :type”;  
  14.         return getSession().createQuery(hql)  
  15.                 .setString(”type”“%” + type + “%”)  
  16.                 .setFirstResult((page-1) * size) //从第几个开始显示  
  17.                 .setMaxResults(size) //显示几个  
  18.                 .list();  
  19.     }  
  20. }  
//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();
    }
}
        我们在测试类中测试一下:

  1. @RunWith(SpringJUnit4ClassRunner.class)  
  2. @ContextConfiguration(locations=“classpath:beans.xml”)  
  3. public class CategoryServiceImplTest {  
  4.   
  5.     @Resource  
  6.     private CategoryService categoryService;  
  7.   
  8.     @Test  
  9.     public void testQueryJoinAccount() {  
  10.         for(Category c : categoryService.queryJoinAccount(“”,1,2)) { //显示第一页,每页2条数据  
  11.             System.out.println(c + ”,” + c.getAccount());  
  12.         }  
  13.     }  
  14. }  
@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


document.getElementById("bdshell_js").src = "http://bdimg.share.baidu.com/static/js/shell_v2.js?cdnversion=" + Math.ceil(new Date()/3600000)
    <div id="digg" articleid="51320212">
        <dl id="btnDigg" class="digg digg_enable" onclick="btndigga();">

             <dt>顶</dt>
            <dd>8</dd>
        </dl>


        <dl id="btnBury" class="digg digg_enable" onclick="btnburya();">

              <dt>踩</dt>
            <dd>1</dd>               
        </dl>

    </div>
 <div class="tracking-ad" data-mod="popu_222"><a href="javascript:void(0);" target="_blank">&nbsp;</a>   </div>
<div class="tracking-ad" data-mod="popu_223"> <a href="javascript:void(0);" target="_blank">&nbsp;</a></div>
<script type="text/javascript">
            function btndigga() {
                $(".tracking-ad[data-mod='popu_222'] a").click();
            }
            function btnburya() {
                $(".tracking-ad[data-mod='popu_223'] a").click();
            }
        </script>

<div style="clear:both; height:10px;"></div>


    <div class="similar_article" style="">
            <h4>我的同类文章</h4>
            <div class="similar_c" style="margin:20px 0px 0px 0px">
                <div class="similar_c_t">
                            <label class="similar_cur">
                                <span style="cursor:pointer" onclick="GetCategoryArticles('6228419','eson_15','foot','51320212');">●  项目实战<em>(29)</em></span>
                            </label>
                            <label class="">
                                <span style="cursor:pointer" onclick="GetCategoryArticles('6214186','eson_15','foot','51320212');">------【SSH网上商城】<em>(29)</em></span>
                            </label>
                </div>

                <div class="similar_wrap tracking-ad" data-mod="popu_141" style="max-height:195px;">
                    <a href="http://blog.csdn.net" style="display:none" target="_blank">http://blog.csdn.net</a>
                    <ul class="similar_list fl"><li><em>•</em><a href="http://blog.csdn.net/eson_15/article/details/51506334" id="foot_aritcle_51506334undefined8646364672056157" target="_blank" title="【SSH网上商城项目实战29】使用JsChart技术在后台显示商品销售报表">【SSH网上商城项目实战29】使用JsChart技术在后台显示商品销售报表</a><span>2016-05-26</span><label><i>阅读</i><b>6059</b></label></li> <li><em>•</em><a href="http://blog.csdn.net/eson_15/article/details/51484247" id="foot_aritcle_51484247undefined3252401155564473" target="_blank" title="【SSH网上商城项目实战27】域名空间的申请和项目的部署及发布">【SSH网上商城项目实战27】域名空间的申请和项目的部署及发布</a><span>2016-05-23</span><label><i>阅读</i><b>13823</b></label></li> <li><em>•</em><a href="http://blog.csdn.net/eson_15/article/details/51475431" id="foot_aritcle_51475431undefined622255979813773" target="_blank" title="【SSH网上商城项目实战26】完成订单支付后的短信发送功能">【SSH网上商城项目实战26】完成订单支付后的短信发送功能</a><span>2016-05-22</span><label><i>阅读</i><b>4704</b></label></li> <li><em>•</em><a href="http://blog.csdn.net/eson_15/article/details/51465067" id="foot_aritcle_51465067undefined6830295366851318" target="_blank" title="【SSH网上商城项目实战24】Struts2中如何处理多个Model请求">【SSH网上商城项目实战24】Struts2中如何处理多个Model请求</a><span>2016-05-21</span><label><i>阅读</i><b>4245</b></label></li> <li><em>•</em><a href="http://blog.csdn.net/eson_15/article/details/51452243" id="foot_aritcle_51452243undefined015048615589963399" target="_blank" title="【SSH网上商城项目实战22】获取银行图标以及支付页面的显示">【SSH网上商城项目实战22】获取银行图标以及支付页面的显示</a><span>2016-05-19</span><label><i>阅读</i><b>3742</b></label></li> <li><em>•</em><a href="http://blog.csdn.net/eson_15/article/details/51441431" id="foot_aritcle_51441431undefined497891591596862" target="_blank" title="【SSH网上商城项目实战20】在线支付平台的介绍">【SSH网上商城项目实战20】在线支付平台的介绍</a><span>2016-05-18</span><label><i>阅读</i><b>4107</b></label></li> </ul>

                    <ul class="similar_list fr"><li><em>•</em><a href="http://blog.csdn.net/eson_15/article/details/51487323" id="foot_aritcle_51487323undefined3447590191259431" target="_blank" title="【SSH网上商城项目实战28】使用Ajax技术局部更新商品数量和总价">【SSH网上商城项目实战28】使用Ajax技术局部更新商品数量和总价</a><span>2016-05-24</span><label><i>阅读</i><b>5337</b></label></li> <li><em>•</em><a href="http://blog.csdn.net/eson_15/article/details/51479994" id="foot_aritcle_51479994undefined10602583116146924" target="_blank" title="【SSH网上商城项目实战30】项目总结(附源码下载地址)">【SSH网上商城项目实战30】项目总结(附源码下载地址)</a><span>2016-05-27</span><label><i>阅读</i><b>21890</b></label></li> <li><em>•</em><a href="http://blog.csdn.net/eson_15/article/details/51475046" id="foot_aritcle_51475046undefined1108231131152384" target="_blank" title="【SSH网上商城项目实战25】使用java email给用户发送邮件">【SSH网上商城项目实战25】使用java email给用户发送邮件</a><span>2016-05-22</span><label><i>阅读</i><b>4007</b></label></li> <li><em>•</em><a href="http://blog.csdn.net/eson_15/article/details/51464415" id="foot_aritcle_51464415undefined63728464073096" target="_blank" title="【SSH网上商城项目实战23】完成在线支付功能">【SSH网上商城项目实战23】完成在线支付功能</a><span>2016-05-20</span><label><i>阅读</i><b>8822</b></label></li> <li><em>•</em><a href="http://blog.csdn.net/eson_15/article/details/51447492" id="foot_aritcle_51447492undefined12226274837349105" target="_blank" title="【SSH网上商城项目实战21】从Demo中看易宝支付的流程">【SSH网上商城项目实战21】从Demo中看易宝支付的流程</a><span>2016-05-18</span><label><i>阅读</i><b>9653</b></label></li> </ul>
                <a href="http://blog.csdn.net/eson_15/article/category/6228419" class="MoreArticle">更多文章</a></div>
            </div>
        </div>    
<script type="text/javascript">
    $(function () {
        GetCategoryArticles('6228419', 'eson_15','foot','51320212');
    });
</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值