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


     

    转自: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的方法了,完成了对商品类别的级联查询和分页功能。

  • 相关阅读:
    Java流程控制语句
    Linux文件过滤及内容编辑处理
    Java运算符优先级
    Java位运算基础知识
    【Linux】【FastDFS】FastDFS安装
    【Linux】【redis】redis安装及开启远程访问
    【Linux】【sonarqube】安装sonarqube7.9
    【Linux】【PostgreSQL】PostgreSQL安装
    【Linux】【maven】maven及maven私服安装
    【Linux】【jenkins】自动化运维七 整合sonarqube代码审查
  • 原文地址:https://www.cnblogs.com/sunshine5683/p/9910647.html
Copyright © 2020-2023  润新知