Hibernate:n + 1个查询问题 - OneToOne关联

时间:2016-07-13 08:00:26

标签: java hibernate orm

已经在google上研究过这个问题,看起来我的代码中存在一切,但代码中仍然存在n + 1个查询问题。尝试了所有可用的建议/解决方法,但每次都有相同的结果。请让我知道我哪里出错了。

下面只是一个示例示例(带有n + 1问题的工作代码)

User.java

@Entity
@Table(name = "USER_DETAILS")
public class User implements Serializable {

    private int userId;
    private String firstName;
    private String lastName;
    private UserLvl userLvl;

    public User() {
    }

    public User(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "USERID")
    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    @Column(name = "FIRST_NAME", length = 50, nullable = false)
    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    @Column(name = "LAST_NAME", length = 50, nullable = false)
    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    @OneToOne(fetch = FetchType.LAZY, mappedBy = "user", cascade = CascadeType.ALL)
    @Fetch(FetchMode.JOIN)
    public UserLvl getUserLvl() {
        return userLvl;
    }

    public void setUserLvl(UserLvl userLvl) {
        this.userLvl = userLvl;
    }

}

UserLvl.java

@Entity
@Table(name = "USER_LEVEL")
public class UserLvl implements Serializable {

    private User user;
    private String lvl;

    public UserLvl() {
    }

    public UserLvl(User user, String lvl) {
        this.user = user;
        this.lvl = lvl;
    }

    @Id
    @OneToOne
    @JoinColumn(name = "USERID")
    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Column(name = "USER_LVL", length = 10)
    public String getLvl() {
        return lvl;
    }

    public void setLvl(String lvl) {
        this.lvl = lvl;
    }

}

UserDao.java

public class UserDao {

    public void addUser(User user) {
        Transaction tx = null;
        Session session = HibernateUtils.getSessionFactory().openSession();

        try {
            tx = session.beginTransaction();
            session.save(user);
            tx.commit();
        } catch (Exception e) {
            if (tx != null) {
                tx.rollback();
            }
        } finally {
            session.close();
        }
    }

    public List<User> getAllUsers() {
        List<User> users = new ArrayList();

        Transaction tx = null;
        Session session = HibernateUtils.getSessionFactory().openSession();

        try {
            tx = session.beginTransaction();
            Criteria criteria = session.createCriteria(User.class);
            users = criteria.list();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (tx != null) {
                tx.commit();
            }
            session.close();
        }

        return users;
    }

}

TestingHibernate.java(带主要的类)

public class TestingHibernate {

    public static void main(String[] args) {

        HibernateUtils.initSessionFactory();

        List<User> users = new ArrayList<>();

        UserDao uDao1 = new UserDao();
        users = uDao1.getAllUsers();

        ListIterator i = users.listIterator();

        while (i.hasNext()) {
            User u = (User) i.next();
            System.out.println(u.getFirstName() + " " + u.getLastName());
        }

        HibernateUtils.getSessionFactory().close();
    }
}

输出:

Hibernate Session Factory is created

Hibernate: 
    /* criteria query */ select
        this_.USERID as USERID1_0_1_,
        this_.FIRST_NAME as FIRST_NA2_0_1_,
        this_.LAST_NAME as LAST_NAM3_0_1_,
        userlvl2_.USERID as USERID2_1_0_,
        userlvl2_.USER_LVL as USER_LVL1_1_0_ 
    from
        USER_DETAILS this_ 
    left outer join
        USER_LEVEL userlvl2_ 
            on this_.USERID=userlvl2_.USERID

Hibernate: 
    select
        userlvl0_.USERID as USERID2_1_0_,
        userlvl0_.USER_LVL as USER_LVL1_1_0_ 
    from
        USER_LEVEL userlvl0_ 
    where
        userlvl0_.USERID=?

Hibernate: 
    select
        userlvl0_.USERID as USERID2_1_0_,
        userlvl0_.USER_LVL as USER_LVL1_1_0_ 
    from
        USER_LEVEL userlvl0_ 
    where
        userlvl0_.USERID=?

Hibernate: 
    select
        userlvl0_.USERID as USERID2_1_0_,
        userlvl0_.USER_LVL as USER_LVL1_1_0_ 
    from
        USER_LEVEL userlvl0_ 
    where
        userlvl0_.USERID=?

Person One
Person Two
Person Three

数据库中的数据:

Table: USER_DETAILS
---------------------------------
USERID | FIRST_NAME | LAST_NAME | 
---------------------------------
1      | Person     | One
2      | Person     | Two
3      | Person     | Three


Table: USER_LEVEL
-----------------
USERID | USER_LVL 
-----------------
1      | Level1
2      | Level2
3      | Level3

看起来Fetch Mode JOIN也正常工作但我仍然有三个选择用于子表,当用户更多时会占用大量资源。 我可能会犯一个非常愚蠢的错误,但仍然想要更多的眼睛来调查,以便找到错误。

0 个答案:

没有答案