在多对多关系中改善Hibernete的表现

时间:2013-04-05 14:02:53

标签: java hibernate java-ee

我有两个表与多对多关系连接。数据库是在另一台服务器上设置的,当我试图获取有关其中一条记录的信息时,如果这些信息包含第二个表的总计数,我就会看到非常大的性能问题。

第一个豆:

package dbaccess.beans.newsletter;

import java.sql.Timestamp;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Column;
import javax.persistence.Table;

import dbaccess.beans.RegisteredUser;

@Entity
@Table(name="NEWSLETTER_LIST")
public class NewsletterList {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "G1")
    @SequenceGenerator(name = "G1", sequenceName = "NEWSLETTER_LIST_SEQ", allocationSize = 1, initialValue= 1)
    @Column(name = "LIST_ID", unique = true, nullable = false)
    private Long listID;

    @Column(name = "LIST_NAME", nullable = false, length = 50)
    private String listName;

    @ManyToMany(fetch = FetchType.LAZY, cascade = {})
    @JoinTable(name = "NEWSLETTERLISTS_USERS", joinColumns = { 
            @JoinColumn(name = "LIST_ID", nullable = false) }, 
            inverseJoinColumns = { @JoinColumn(name = "USER_ID", nullable = false) })
    private Set<RegisteredUser> users = new HashSet<RegisteredUser>(0);

    public Long getListID() {
        return listID;
    }

    public void setListID(Long listID) {
        this.listID = listID;
    }

    public Set<RegisteredUser> getUsers() {
        return users;
    }

    public void setUsers(Set<RegisteredUser> users) {
        this.users = users;
    }

}

第二个豆子:

package dbaccess.beans;

import java.sql.Timestamp;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Column;
import javax.persistence.Table;

import dbaccess.beans.newsletter.NewsletterList;

@Entity
@Table(name="USER")
public class RegisteredUser {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "G1")
    @SequenceGenerator(name = "G1", sequenceName = "USER_SEQ", allocationSize = 1, initialValue= 1)
    @Column(name = "USER_ID", unique = true, nullable = false)
    private Long usrID;

    @Column(name = "GIVENNAME", length = 20)
    private String usrGivenName;

    @Column(name = "FAMILYNAME", length = 20)
    private String usrFamilyName;

    @ManyToMany(fetch = FetchType.EAGER, mappedBy = "users", cascade = {})
    public Set<NewsletterList> newsletterList = new HashSet<NewsletterList>();

    public Long getUsrID() {
        return usrID;
    }

    public void setUsrID(Long usrID) {
        this.usrID = usrID;
    }

    public String getUsrGivenName() {
        return usrGivenName;
    }

    public void setUsrGivenName(String usrGivenName) {
        this.usrGivenName = usrGivenName;
    }

    public String getUsrFamilyName() {
        return usrFamilyName;
    }

    public void setUsrFamilyName(String usrFamilyName) {
        this.usrFamilyName = usrFamilyName;
    }

    public Set<NewsletterList> getNewsletterList() {
        return newsletterList;
    }

    public void setNewsletterList(Set<NewsletterList> newsletterList) {
        this.newsletterList = newsletterList;
    }

    @Override
    public String toString() {
        return "RegisteredUser[usrID=" + usrID + ", usrGivenName=" + usrGivenName + ", usrFamilyName=" + usrFamilyName + "]";
    }

}

问题是当我尝试执行这段代码时:

session = dbService.getSessionFactory().openSession();
Criteria c = session.createCriteria(NewsletterList.class);
c.add(Restrictions.eq("listID", listID));
List<NewsletterList> newsletterList = (List<NewsletterList>) c.list();

//below is most expensive
newsletterList.get(0).getUsers().size()

有没有办法改善这种表现? 提前谢谢。

PS当我有约。一个列表中的70个用户,对上述代码的请求大约需要5-6秒!

3 个答案:

答案 0 :(得分:2)

newsletterList.get(0).getUsers().size()使Hibernate加载注册到时事通讯的所有用户,只是为了获得注册用户的数量。

使用临时HQL查询来计算注册用户数:

select count(user.usrID) from RegisteredUser user
inner join user.newsletterList newsLetter
where newsLetter.listID = :listId

请注意,执行上述代码5-6秒的方式太多了。您可能需要检查连接表的连接列上是否有索引。

另请注意,您只需使用session.get(NewsLetter.class, listId)按ID获取列表。

最后,如果您的ID都被命名为id,那么一切都会更容易,更易读。

答案 1 :(得分:0)

您可能希望尝试使用Hibernate Criteria API来查询特定简报上的用户数量。它看起来大致如下:

Criteria crit = session.createCriteria(RegisteredUser.class);
crit.setProjection(Projections.rowCount());
crit.add(Restrictions.eq("listID", listID));
return (Long) crit.uniqueResult(); 

答案 2 :(得分:0)