使用flushMode=autoHibernate查询要慢得多,直到CLEAR()被调用?

  • 回答 (2)
  • 关注 (0)
  • 查看 (12)

部分代码

Place place = em.createQuery("from Place where name = :name", Place.class)
    .setParameter("name", name)
    .setFlushMode(FlushModeType.COMMIT)  // <-- yay!
    .getSingleResult();

示例代码如下:

测试实体

@Entity @Table(name="place") @Immutable
public class Place {
    private Long _id;
    private String _name;

    @Id @GeneratedValue
    public Long getId() { return _id; }
    public void setId(Long id) { _id = id; }

    @Basic(optional=false) @Column(name="name", length=700,
        updatable=false, nullable=false, unique=true,
        columnDefinition="varchar(700) character set 'ascii' not null")
    public String getName() { return _name; }
    public void setName(String name) { _name = name; }

    @Override
    public boolean equals(Object o) { /* ... */ }

    @Override
    public int hashCode() { return getName().hashCode(); }
}

基准代码

我的测试代码生成100000个随机地名并插入它们。然后随机查询其中5000的名字。Name列上有一个索引。

Place place = em.createQuery(
    "select p from Place p where p.name = :name", Place.class)
    .setParameter("name", name)
    .getSingleResult();

在另一个随机选择数据:

PreparedStatement ps = c.prepareStatement(
    "select id, name from place where name = ?");
ps.setString(1, name);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
    Place place = new Place();
    place.setId(rs.getLong(1));
    place.setName(rs.getString(2));
}
rs.close();
ps.close();

结果

下面的所有结果平均超过5000次查询

Seconds/Query    Approach
0.000160s        JDBC
0.000286s        Hibernate calling clear() after import and every 100 queries
0.000653s        Hibernate calling clear() once after the import
0.012533s        Hibernate w/o calling clear() at all
0.000292s        Hibernate w/o calling clear(), and with flush-mode COMMIT
BlackKnightBlackKnight提问于
凤凰男显示回答于

可以使用StatelessSession它的设计是为了解决这些性能上的问题。可以通过:

StatelessSession session = ((Session) entityManager.getDelegate()).getSessionFactory().openStatelessSession();

ipwut回答于

准备查询的刷新调用结果如下:

DefaultFlushEventListener.onFlush(..)

执行:

for ( Map.Entry me : IdentityMap.concurrentEntries( persistenceContext.getEntityEntries() ) ) {
        EntityEntry entry = (EntityEntry) me.getValue();
        Status status = entry.getStatus();
        if ( status == Status.MANAGED || status == Status.SAVING || status == Status.READ_ONLY ) {
            cascadeOnFlush( session, entry.getPersister(), me.getKey(), anything );
        }
    }

cascadeOnFlush的代码:

private void cascadeOnFlush(EventSource session, EntityPersister persister, Object object, Object anything)
throws HibernateException {
    session.getPersistenceContext().incrementCascadeLevel();
    try {
        new Cascade( getCascadingAction(), Cascade.BEFORE_FLUSH, session )
        .cascade( persister, object, anything );
    }
    finally {
        session.getPersistenceContext().decrementCascadeLevel();
    }
}

扫码关注云+社区