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

上一节我们完成了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 );

主要有两张表,商品类别表和管理员表,并且商品类别表中提供了一个外键关联管理员表。也就是商品和管理员是多对一的关系。现在我们开始编写查询商品的类别信息,需要级联管理员。

1. 实现级联查询方法
        首先在CategoryService接口中定义该方法:

 1 public interface CategoryService extends BaseService<Category> {
2 //查询类别信息,级联管理员
3 public List<Category> queryJoinAccount(String type); //使用类别的名称查询
4 }
5 然后我们在CategoryService的实现类CategoryServiceImpl中实现这个方法:
6
7
8
9
10
11 @Service("categoryService")
12 public class CategoryServiceImpl extends BaseServiceImpl<Category> implements CategoryService {
13
14 @Override
15 public List<Category> queryJoinAccount(String type) {
16 String hql = "from Category c where c.type like :type";
17 return getSession().createQuery(hql)
18 .setString("type", "%" + type + "%").list();
19 }
20 }

在两个Model中我们配一下关联注解:

//Category类中

  1 package cn.it.shop.model;
2
3 import java.util.Set;
4
5 import javax.persistence.Column;
6 import javax.persistence.Entity;
7 import javax.persistence.FetchType;
8 import javax.persistence.GeneratedValue;
9 import javax.persistence.Id;
10 import javax.persistence.JoinColumn;
11 import javax.persistence.ManyToOne;
12
13
14 /**
15 * Category entity. @author MyEclipse Persistence Tools
16 */
17 @Entity
18 public class Category implements java.io.Serializable {
19
20 // Fields
21
22 private Integer id;
23 private Account account;
24 private String type;
25 private Boolean hot;
26 // private Set<Product> products = new HashSet<Product>(0);
27
28
29 // Constructors
30
31 /** default constructor */
32 public Category() {
33 }
34
35 @Override
36 public String toString() {
37 return "Category [id=" + id + ", account=" + account + ", type=" + type
38 + ", hot=" + hot + "]";
39 }
40
41 /** full constructor */
42 public Category(Account account, String type, Boolean hot,
43 Set<Product> products) {
44 this.account = account;
45 this.type = type;
46 this.hot = hot;
47 // this.products = products;
48 }
49
50 public Category(Integer id, String type, Boolean hot) {
51 super();
52 this.id = id;
53 this.type = type;
54 this.hot = hot;
55 }
56
57 public Category(String type, Boolean hot) {
58 super();
59 this.type = type;
60 this.hot = hot;
61 }
62
63 // Property accessors
64 @Id
65 @GeneratedValue
66 @Column(name = "id", unique = true, nullable = false)
67 public Integer getId() {
68 return this.id;
69 }
70
71 public void setId(Integer id) {
72 this.id = id;
73 }
74
75 @ManyToOne(fetch = FetchType.LAZY)
76 @JoinColumn(name = "aid")
77 public Account getAccount() {
78 return this.account;
79 }
80
81 public void setAccount(Account account) {
82 this.account = account;
83 }
84
85 @Column(name = "type", length = 20)
86 public String getType() {
87 return this.type;
88 }
89
90 public void setType(String type) {
91 this.type = type;
92 }
93
94 @Column(name = "hot")
95 public Boolean getHot() {
96 return this.hot;
97 }
98
99 public void setHot(Boolean hot) {
100 this.hot = hot;
101 }
102
103 // @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "category")
104 // public Set<Product> getProducts() {
105 // return this.products;
106 // }
107 //
108 // public void setProducts(Set<Product> products) {
109 // this.products = products;
110 // }
111
112 }

//Account类中

  1 package cn.it.shop.model;
2
3 import java.util.HashSet;
4 import java.util.Set;
5
6 import javax.persistence.CascadeType;
7 import javax.persistence.Column;
8 import javax.persistence.Entity;
9 import javax.persistence.FetchType;
10 import javax.persistence.GeneratedValue;
11 import javax.persistence.Id;
12 import javax.persistence.OneToMany;
13 import javax.persistence.Table;
14
15 /**
16 * Account entity. @author MyEclipse Persistence Tools
17 */
18 @Entity
19 public class Account implements java.io.Serializable {
20
21 // Fields
22
23 private Integer id;
24 private String login;
25 private String name;
26 private String pass;
27 // private Set<Category> categories = new HashSet<Category>(0);
28
29
30 // Constructors
31
32 /** default constructor */
33 public Account() {
34 }
35
36 @Override
37 public String toString() {
38 return "Account [id=" + id + ", login=" + login + ", name=" + name
39 + ", pass=" + pass + "]";
40 }
41
42 /** full constructor */
43 public Account(String login, String name, String pass,
44 Set<Category> categories) {
45 this.login = login;
46 this.name = name;
47 this.pass = pass;
48 // this.categories = categories;
49 }
50
51
52 public Account(String login, String name, String pass) {
53 super();
54 this.login = login;
55 this.name = name;
56 this.pass = pass;
57 }
58
59 // Property accessors
60 @Id
61 @GeneratedValue
62 @Column(name = "id", unique = true, nullable = false)
63 public Integer getId() {
64 return this.id;
65 }
66
67 public void setId(Integer id) {
68 this.id = id;
69 }
70
71 @Column(name = "login", length = 20)
72 public String getLogin() {
73 return this.login;
74 }
75
76 public void setLogin(String login) {
77 this.login = login;
78 }
79
80 @Column(name = "name", length = 20)
81 public String getName() {
82 return this.name;
83 }
84
85 public void setName(String name) {
86 this.name = name;
87 }
88
89 @Column(name = "pass", length = 20)
90 public String getPass() {
91 return this.pass;
92 }
93
94 public void setPass(String pass) {
95 this.pass = pass;
96 }
97
98 // @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "account")
99 // public Set<Category> getCategories() {
100 // return this.categories;
101 // }
102 //
103 // public void setCategories(Set<Category> categories) {
104 // this.categories = categories;
105 // }
106
107 }

然后我们在测试类中测试一下:

 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 }

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 }

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 }

我们在测试类中测试一下:

 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 }

为此,我们写完了Service的方法了,完成了对商品类别的级联查询和分页功能。

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

  1. 【SSH网上商城项目实战30】项目总结

      转自:https://blog.csdn.net/eson_15/article/details/51479994 0. 写在前面 项目基本完成了,加上这个总结,与这个项目相关的博客也写了30篇了 ...

  2. 【SSH网上商城项目实战30】项目总结(附源码下载地址)

    项目基本完成了,加上这个总结,与这个项目相关的博客也写了30篇了,积少成多,写博客的过程是固化思路的一个过程,对自己很有用,同时也能帮助别人.顺便说个题外话,在学习的过程中肯定会遇到很多异常出现,我们 ...

  3. 【SSH网上商城项目实战27】域名空间的申请和项目的部署及发布

     转自:https://blog.csdn.net/wwww_com/article/details/54405355 前面陆陆续续的完成了网上商城的一些基本功能,虽然还有很多地方有待完善,但是不影响 ...

  4. 【SSH网上商城项目实战16】Hibernate的二级缓存处理首页的热门显示

    转自:https://blog.csdn.net/eson_15/article/details/51405911 网上商城首页都有热门商品,那么这些商品的点击率是很高的,当用户点击某个热门商品后需要 ...

  5. 【SSH网上商城项目实战21】从Demo中看易宝支付的流程

         转自: https://blog.csdn.net/eson_15/article/details/51447492 这一节我们先写一个简单点的Demo来测试易宝支付的流程,熟悉这个流程后, ...

  6. 【SSH网上商城项目实战01】整合Struts2、Hibernate4.3和Spring4.2

    转自:https://blog.csdn.net/eson_15/article/details/51277324 今天开始做一个网上商城的项目,首先从搭建环境开始,一步步整合S2SH.这篇博文主要总 ...

  7. 【SSH网上商城项目实战25】使用java email给用户发送邮件

       转自: https://blog.csdn.net/eson_15/article/details/51475046 当用户购买完商品后,我们应该向用户发送一封邮件,告诉他订单已生成之类的信息, ...

  8. 【SSH网上商城项目实战15】线程、定时器同步首页数据(类似于博客定期更新排名)

    转自:https://blog.csdn.net/eson_15/article/details/51387378 上一节我们做完了首页UI界面,但是有个问题:如果我在后台添加了一个商品,那么我必须重 ...

  9. 【SSH网上商城项目实战14】商城首页UI的设计

    转自:https://blog.csdn.net/eson_15/article/details/51373403 前面我们利用EasyUI和SSH搭建好了后台的基本框架,做好了后台的基本功能,包括对 ...

随机推荐

  1. C语言多线程编程一

    1. Windows下同时打开多个对话框: #include <Windows.h> #include <process.h> //创建线程 void runmsg(void ...

  2. iOS 计算文字宽度的一个细节

    设计师给到的图,经常是 "按钮的左边距离文字右边5px" 这样子的标注.于是我们需要计算文字的宽度. 有两种方法: 用 label 或 button 的 sizetofit 方法 ...

  3. python 开发工具IDE pycharm的破解版安装

    打开终端 cd /etc 命令行输入 sudo vim hosts 输入mac密码 输入i,进入编辑模式(注意在英文状态下书写) 粘贴0.0.0.0 account.jetbrains.com到文件最 ...

  4. 3.1 High Availability

    摘要: 出处:黑洞中的奇点 的博客 http://www.cnblogs.com/kelvin19840813/ 您的支持是对博主最大的鼓励,感谢您的认真阅读.本文版权归作者所有,欢迎转载,但请保留该 ...

  5. mac安装gdb调试(转载)

    转载自:http://blog.plotcup.com/a/129 最近一直用go写一个项目,本想在mac上用gdb调试一下,但xcode4.6带的gdb版 本还是太低了,不支持go,只好自己安装一个 ...

  6. Java多线程——对象组合

    我们不希望对每一次的内存访问都进行分析以确保程序是线程安全的,而是希望将一些现有的线程安全组件组合为更大规模的组件或者程序,这里介绍一些组合模式,这些组合模式能够使一个类更容易成为线程安全的,并且在维 ...

  7. ownCloud问题处理server replied 423 Locked to

    打开owncloud 数据库备份:oc_file_locks表(备份免错哦)然后清空该表,客户端同步一次,故障解决 owncloud大的数据无法同步..

  8. java 字符串(String)常用技巧及自建方法模块汇总

    1.String类常用方法汇总 (1)删除字符串的头尾空白符 public String trim() (2)从指定位置截取字符串 public String substring(int beginI ...

  9. 厉害了,七牛云 CEO 来讲架构了!

    说起许式伟,你应该不陌生,他是七牛云的CEO,ECUG 社区发起人,国内 Go 语言圈的领军人物,曾就职于金山.盛大,有超过 10 年的搜索和分布式存储相关技术的研发经验. 他的个人经历颇为传奇,大学 ...

  10. loj 6433 「PKUSC2018」最大前缀和 题解【DP】【枚举】【二进制】【排列组合】

    这是个什么集合DP啊- 想过枚举断点但是不会处理接下来的问题了- 我好菜啊 题目描述 小 C 是一个算法竞赛爱好者,有一天小 C 遇到了一个非常难的问题:求一个序列的最大子段和. 但是小 C 并不会做 ...