0

我正在分析我的应用程序的性能,我注意到以下内容。我有这个查询:

public List<Rol> findAll() {
        return mySessionFactory.getCurrentSession().createQuery("from Rol").list();
    }

这将返回此查询:

SELECT rol0_._id as column1_2_, rol0_.description as descripc2_2_, rol0_.name as nombre6_2_, rol0_.status as status7_2_ FROM rol rol0_

这很好,但在我的jsp中我有以下内容:

<form:select multiple="true" path="roles" required="true">
                    <form:options items="${roles}" itemValue="id" itemLabel="nombre" />
                </form:select>

这会为每个角色创建一个新查询:

DEBUG: org.hibernate.SQL - select rol0_._id as column1_2_0_, rol0_.description as descripc2_2_0_, rol0_.name as name6_2_0_, rol0_.status as status7_2_0_ from rol rol0_ where rol0_._id=?
TRACE: org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [1] as [VARCHAR] - 1
DEBUG: org.hibernate.SQL - select rol0_._id as column1_2_0_, rol0_.description as descripc2_2_0_, rol0_.name as name6_2_0_, rol0_.status as status7_2_0_ from rol rol0_ where rol0_._id=?
TRACE: org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [1] as [VARCHAR] - 2
DEBUG: org.hibernate.SQL - select rol0_._id as column1_2_0_, rol0_.description as descripc2_2_0_, rol0_.name as name_2_0_, rol0_.status as status7_2_0_ from rol rol0_ where rol0_._id=?
TRACE: org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [1] as [VARCHAR] - 20130915150706256
DEBUG: org.hibernate.SQL - select rol0_._id as column1_2_0_, rol0_.description as descripc2_2_0_, rol0_.name as name6_2_0_, rol0_.status as status7_2_0_ from rol rol0_ where rol0_._id=?
TRACE: org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [1] as [VARCHAR] - 3

在我的控制器中,我有:

List<Rol> roles = rolDao.findAll();
ModelAndView mav = new ModelAndView("usuarioNew");
mav.getModelMap().put("roles", roles);

有什么办法可以避免这种情况吗?第一个查询包含我需要的所有信息,我不想要额外的查询。

编辑:

@Entity
@Table(name = "rol", uniqueConstraints = { @UniqueConstraint(columnNames = "name") })
public class Rol implements Serializable{

    @Id
    @Column(name = "_id")
    private String id;

    @Column(name = "name")
    @NotEmpty
    private String name;

    @Column(name = "description")
    private String description;

    @Column(name = "status")
    private String status;


    @NotEmpty
    @Fetch(FetchMode.JOIN)
    @OneToMany(mappedBy = "rolPermission_pk.rol", orphanRemoval = true, cascade=CascadeType.ALL)
    private Set<Rol_Permission> permissions = new HashSet<Rol_Permission>(0);

    ....//getters, setters
    }

编辑2:

public class UserRolCollectionEditor extends CustomCollectionEditor {

     private final RolDAO rolDao;


    public UserRolCollectionEditor (Class<?> collectionType, RolDAO rolDao) {

        super(collectionType);
        this.rolDao = rolDao;

    }

    @Override
    protected Object convertElement(Object element) {
        String rolId = (String) element;

        Rol rol = rolDao.findById(rolId);
        User_Rol usuRol = new User_Rol();


        User user = new User();

        usuRol.setUser(user);
        usuRol.setRol(rol);
        usuRol.setStatus("active");

        return usuRol;
    }

}

编辑3:

我做了一些测试,问题出在 UserRolCollectionEditor 和 @Fetch(FetchMode.JOIN) 上。如果我从代码中删除 UserRolCollectionEditor 和 @Fetch(FetchMode.JOIN),我会得到一个查询。如果只删除 @Fetch(FetchMode.JOIN) 我会得到额外的查询。如果仅删除 UserRolCollectionEditor 我会收到额外的查询..我不知道该怎么做..

4

1 回答 1

1

我不能说为什么 hibernate 会生成过多的查询,但它们是由于在您的 JSP 中访问 ${roles} 时存在持久性上下文(即打开会话)而创建的。为了防止这种行为,您可以尝试事先关闭会话(我认为这更像是一种解决方法,而不是您的解决方案)。有几种方法可以实现(使用每请求会话模式):

  • 在你的 DAO 中使用 mySessionFactory.openSession() 和 mySessionFactory.closeSession();
  • 在你的 DAO 中使用 getCurrentSession().beginTransaction() 和 getCurrentSession().commitTransaction();
  • 创建服务层并让 Spring 管理事务。

很棒的 spring 分层 webapp 示例

在 Hibernate 中处理会话和事务

更新

如果在底层使用 inline 可以创建选择UserRolCollectionEditor查询。如果是这种情况,您可以将其更改为,以避免额外的查询。简而言之,for 的常见使用场景是在实体对象之间创建关联——这正是您在方法中所做的。Rol rol = rolDao.findById(rolId);session.get()rolDaosession.load()session.load()UserRolCollectionEditor.convertElement()

简短的文章显示了 get 和 load 之间的区别

于 2013-09-17T04:36:09.407 回答