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

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

猜你喜欢

转载自www.cnblogs.com/sunshine5683/p/9910647.html
今日推荐