上一節我們完成了EasyUI菜單的實現。這一節我們主要來寫一下CategoryServiceImpl實現類,完成數據庫的級聯查詢。一般項目從后往前做,先做service(我們沒有抽取Dao,最后再抽取),做完了再做上面層。

  在寫之前,先看一下數據庫中的表的情況:

SQL代碼
  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接口中定義該方法:

Java代碼
  1. public interface CategoryService extends BaseService<Category> {    
  2.     //查詢類別信息,級聯管理員    
  3.     public List<Category> queryJoinAccount(String type); //使用類別的名稱查詢    
  4. }   

  然后我們在CategoryService的實現類CategoryServiceImpl中實現這個方法:

Java代碼
  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. }    

  在兩個Model中我們配一下關聯注解:

Java代碼
  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. }    

  然后我們在測試類中測試一下:

Java代碼
  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實現類:

Java代碼
  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:

Java代碼
  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. }    

  我們在測試類中測試一下:

Java代碼
  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的方法了,完成了對商品類別的級聯查詢和分頁功能。

除非特別注明,雞啄米文章均為原創
轉載請標明本文地址:http://www.cpbsu.com/software/764.html
2017年9月13日
作者:雞啄米 分類:軟件開發 瀏覽: 評論:0