上文我們完成了EasyUI菜單的實(shí)現(xiàn),點(diǎn)擊這里查看,這一節(jié)我們主要來(lái)寫(xiě)一下CategoryServiceImpl實(shí)現(xiàn)類(lèi),完成數(shù)據(jù)庫(kù)的級(jí)聯(lián)查詢。一般項(xiàng)目從后往前做,先做service(我們沒(méi)有抽取Dao,最后再抽取),做完了再做上面層。
在寫(xiě)之前,先看一下數(shù)據(jù)庫(kù)中的表的情況:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
drop database if exists shop; /*創(chuàng)建數(shù)據(jù)庫(kù),并設(shè)置編碼*/ create database shop default character set utf8; use shop; /*刪除管理員表*/ drop table if exists account; /*刪除商品類(lèi)別表*/ drop table if exists category; /*============================*/ /* Table :管理員表結(jié)構(gòu) */ /*============================*/ create table account ( /* 管理員編號(hào),自動(dòng)增長(zhǎng) */ id int primary key not null auto_increment, /* 管理員登錄名 */ login varchar (20), /* 管理員姓名 */ name varchar (20), /* 管理員密碼 */ pass varchar (20) ); /*============================*/ /* Table :商品類(lèi)別表結(jié)構(gòu) */ /*============================*/ create table category ( /* 類(lèi)別編號(hào),自動(dòng)增長(zhǎng) */ id int primary key not null auto_increment, /* 類(lèi)別名稱(chēng) */ type varchar (20), /* 類(lèi)別是否為熱點(diǎn)類(lèi)別,熱點(diǎn)類(lèi)別才有可能顯示在首頁(yè)*/ hot bool default false , /* 外鍵,此類(lèi)別由哪位管理員管理 */ account_id int , constraint aid_FK foreign key (account_id) references account(id) ); |
主要有兩張表,商品類(lèi)別表和管理員表,并且商品類(lèi)別表中提供了一個(gè)外鍵關(guān)聯(lián)管理員表。也就是商品和管理員是多對(duì)一的關(guān)系。現(xiàn)在我們開(kāi)始編寫(xiě)查詢商品的類(lèi)別信息,需要級(jí)聯(lián)管理員。
1. 實(shí)現(xiàn)級(jí)聯(lián)查詢方法
首先在CategoryService接口中定義該方法:
1
2
3
4
|
public interface CategoryService extends BaseService<Category> { //查詢類(lèi)別信息,級(jí)聯(lián)管理員 public List<Category> queryJoinAccount(String type); //使用類(lèi)別的名稱(chēng)查詢 } |
然后我們?cè)贑ategoryService的實(shí)現(xiàn)類(lèi)CategoryServiceImpl中實(shí)現(xiàn)這個(gè)方法:
1
2
3
4
5
6
7
8
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(); } } |
在兩個(gè)Model中我們配一下關(guān)聯(lián)注解:
1
2
3
4
5
6
7
8
9
10
11
|
//Category類(lèi)中 @ManyToOne (fetch = FetchType.EAGER) @JoinColumn (name = "account_id" ) public Account getAccount() { return this .account; } //Account類(lèi)中 @OneToMany (cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "account" ) public Set<Category> getCategories() { return this .categories; } |
然后我們?cè)跍y(cè)試類(lèi)中測(cè)試一下:
1
2
3
4
5
6
7
8
9
10
11
12
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. 級(jí)聯(lián)查詢存在的問(wèn)題
我們看一下控制臺(tái)的輸出可以看出,它發(fā)了不止一條SQL語(yǔ)句,但是我們明明只查詢了一次,為什么會(huì)發(fā)這么多語(yǔ)句呢?這就是常見(jiàn)的1+N問(wèn)題。所謂的1+N問(wèn)題,就是首先發(fā)出一條語(yǔ)句查詢當(dāng)前對(duì)象,然后發(fā)出N條語(yǔ)句查詢關(guān)聯(lián)對(duì)象,因此效率變得很低。這里就兩個(gè)對(duì)象,如果有更多的對(duì)象,那效率就會(huì)大打折扣了,我們?cè)撊绾谓鉀Q這個(gè)問(wèn)題呢?
可能大家會(huì)想到將fetch設(shè)置生FetchType.LAZY就不會(huì)發(fā)多條語(yǔ)句了,但是這肯定不行,因?yàn)樵O(shè)置成LAZY后,我們就拿不到Account對(duì)象了,比較好的解決方法是我們自己寫(xiě)hql語(yǔ)句,使用join fetch。具體看修改后的CategoryServiceImpl實(shí)現(xiàn)類(lèi):
1
2
3
4
5
6
7
8
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表示關(guān)聯(lián)Account一起查詢,fetch表示將Account對(duì)象加到Category中去,這樣就只會(huì)發(fā)一條SQL語(yǔ)句了,并且返回的Category中也包含了Account對(duì)象了。
3. 完成分頁(yè)功能
Hibernate中的分頁(yè)很簡(jiǎn)單,只需要調(diào)用兩個(gè)方法setFirstResult和setMaxResults即可:我們修改一下CategoryService接口和它的實(shí)現(xiàn)類(lèi)CategoryServiceImpl:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
//CategoryService public interface CategoryService extends BaseService<Category> { //查詢類(lèi)別信息,級(jí)聯(lián)管理員 public List<Category> queryJoinAccount(String type, int page, int size); //并實(shí)現(xiàn)分頁(yè) } //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) //從第幾個(gè)開(kāi)始顯示 .setMaxResults(size) //顯示幾個(gè) .list(); } } |
我們?cè)跍y(cè)試類(lèi)中測(cè)試一下:
1
2
3
4
5
6
7
8
9
10
11
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 )) { //顯示第一頁(yè),每頁(yè)2條數(shù)據(jù) System.out.println(c + "," + c.getAccount()); } } } |
為此,我們寫(xiě)完了Service的方法了,完成了對(duì)商品類(lèi)別的級(jí)聯(lián)查詢和分頁(yè)功能。
(注:到最后我會(huì)提供整個(gè)項(xiàng)目的源碼下載!歡迎大家收藏或分享)
原文地址:http://blog.csdn.net/eson_15/article/details/51320212
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。