转自:http://blog.youkuaiyun.com/eson_15/article/details/51320212
上一节我们完成了EasyUI菜单的实现。这一节我们主要来写一下CategoryServiceImpl实现类,完成数据库的级联查询。一般项目从后往前做,先做service(我们没有抽取Dao,最后再抽取),做完了再做上面层。
在写之前,先看一下数据库中的表的情况:
- 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接口中定义该方法:
- 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中实现这个方法:
- @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中我们配一下关联注解:
- //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;
}
然后我们在测试类中测试一下:
- @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实现类:
- @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:
- //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();
}
}
我们在测试类中测试一下:
- @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.youkuaiyun.com/column/details/str2hiberspring.html
整个项目的源码下载地址:http://blog.youkuaiyun.com/eson_15/article/details/51479994
_____________________________________________________________________________________________________________________________________________________
-----乐于分享,共同进步!
-
顶
- 9
-
踩
- 1
我的同类文章
- •【SSH网上商城项目实战29】使用JsChart技术在后台显示商品销售报表2016-05-26
- •【SSH网上商城项目实战27】域名空间的申请和项目的部署及发布2016-05-23
- •【SSH网上商城项目实战26】完成订单支付后的短信发送功能2016-05-22
- •【SSH网上商城项目实战24】Struts2中如何处理多个Model请求2016-05-21
- •【SSH网上商城项目实战22】获取银行图标以及支付页面的显示2016-05-19
- •【SSH网上商城项目实战20】在线支付平台的介绍2016-05-18
- •【SSH网上商城项目实战28】使用Ajax技术局部更新商品数量和总价2016-05-24
- •【SSH网上商城项目实战30】项目总结(附源码下载地址)2016-05-27
- •【SSH网上商城项目实战25】使用java email给用户发送邮件2016-05-22
- •【SSH网上商城项目实战23】完成在线支付功能2016-05-20
- •【SSH网上商城项目实战21】从Demo中看易宝支付的流程2016-05-18