为什么hibernate获取较少行数的速度较慢?

为什么hibernate获取较少行数的速度较慢?,hibernate,jdbc,hibernate-mapping,Hibernate,Jdbc,Hibernate Mapping,我遵循下面列出的hibernate教程 我修改了代码,使用本地mysql作为数据库。之后,我用10000行填充数据库表 我比较了两种类型的数据库读取的延迟——一种是通过hibernate本机查询;其他通过直接JDBC和从ResultSet创建对象 与我的自定义JDBC和java对象映射实现相比,hibernate的速度非常慢,这让我感到非常奇怪。当获取的行数低于10000时会发生这种情况。例如,使用我的方法获取10-100行需要3-18ms,而hibernate大约需要280-320ms。但当我

我遵循下面列出的hibernate教程

我修改了代码,使用本地mysql作为数据库。之后,我用10000行填充数据库表

我比较了两种类型的数据库读取的延迟——一种是通过hibernate本机查询;其他通过直接JDBC和从ResultSet创建对象

与我的自定义JDBC和java对象映射实现相比,hibernate的速度非常慢,这让我感到非常奇怪。当获取的行数低于10000时会发生这种情况。例如,使用我的方法获取10-100行需要3-18ms,而hibernate大约需要280-320ms。但当我尝试获取>10K行时,hibernate会变得高效

有人能解释一下hibernate在做什么导致了这么多的延迟吗

我的hibernate.cfg.xml如下所示

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>

    <!-- Database connection settings -->
    <property name="connection.url">jdbc:mysql://localhost:3306/fquick-task-manager?useSSLx`=false</property>
    <property name="connection.username">root</property>
    <property name="connection.password"/>

    <!-- JDBC connection pool (use the built-in) -->
    <property name="connection.pool_size">15</property>

    <!-- SQL dialect -->
    <property name="dialect">org.hibernate.dialect.MySQLDialect</property>

    <!-- Disable the second-level cache  -->
    <property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>

    <!-- Echo all executed SQL to stdout -->
    <property name="show_sql">true</property>

    <!-- Drop and re-create the database schema on startup -->
    <property name="hbm2ddl.auto">update</property>

    <mapping resource="org/hibernate/tutorial/hbm/Event.hbm.xml"/>

</session-factory>
</hibernate-configuration>
public void testBasicUsage() {

    // Using JDBC
    Session session = sessionFactory.openSession();
    session.beginTransaction();
    String queryStr = "";
    try {
        long start = System.currentTimeMillis();
        Statement statement = ((SessionImpl) session).connection().createStatement();
        queryStr = "select * from Events where EVENT_ID < 10";
        ResultSet rs = statement.executeQuery(queryStr);
        List<Event> events = new ArrayList<Event>();
        while (rs.next()) {
            Long eventId = rs.getLong("EVENT_ID");
            String title = rs.getString("title");
            Date myDate = rs.getDate("EVENT_DATE");
            Event event = new Event(eventId,title ,myDate);
            events.add(event);
        }
        long end = System.currentTimeMillis();
        long timeTaken = end - start;
        System.out.println("Query took " + timeTaken + "ms");

    } catch (SQLException e) {
        System.out.println("Error in statement creation");
    }
    session.getTransaction().commit();
    session.close();

    // Using Hibernate
    session = sessionFactory.openSession();
    session.beginTransaction();
    queryStr = "select * from Events where EVENT_ID > 20 & EVENT_ID < 30";
    long start3 = System.currentTimeMillis();
    session.createSQLQuery(queryStr).list();
    long end3 = System.currentTimeMillis();
    long timeTaken3 = end3 - start3;
    System.out.println("Query took " + timeTaken3 + "ms");
    session.getTransaction().commit();
    session.close();

}

jdbc:mysql://localhost:3306/fquick-任务管理器?useSSLx`=false
根
15
org.hibernate.dialogue.mysqldialogue
org.hibernate.cache.internal.NoCacheProvider
真的
更新
我的测试函数如下所示

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>

    <!-- Database connection settings -->
    <property name="connection.url">jdbc:mysql://localhost:3306/fquick-task-manager?useSSLx`=false</property>
    <property name="connection.username">root</property>
    <property name="connection.password"/>

    <!-- JDBC connection pool (use the built-in) -->
    <property name="connection.pool_size">15</property>

    <!-- SQL dialect -->
    <property name="dialect">org.hibernate.dialect.MySQLDialect</property>

    <!-- Disable the second-level cache  -->
    <property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>

    <!-- Echo all executed SQL to stdout -->
    <property name="show_sql">true</property>

    <!-- Drop and re-create the database schema on startup -->
    <property name="hbm2ddl.auto">update</property>

    <mapping resource="org/hibernate/tutorial/hbm/Event.hbm.xml"/>

</session-factory>
</hibernate-configuration>
public void testBasicUsage() {

    // Using JDBC
    Session session = sessionFactory.openSession();
    session.beginTransaction();
    String queryStr = "";
    try {
        long start = System.currentTimeMillis();
        Statement statement = ((SessionImpl) session).connection().createStatement();
        queryStr = "select * from Events where EVENT_ID < 10";
        ResultSet rs = statement.executeQuery(queryStr);
        List<Event> events = new ArrayList<Event>();
        while (rs.next()) {
            Long eventId = rs.getLong("EVENT_ID");
            String title = rs.getString("title");
            Date myDate = rs.getDate("EVENT_DATE");
            Event event = new Event(eventId,title ,myDate);
            events.add(event);
        }
        long end = System.currentTimeMillis();
        long timeTaken = end - start;
        System.out.println("Query took " + timeTaken + "ms");

    } catch (SQLException e) {
        System.out.println("Error in statement creation");
    }
    session.getTransaction().commit();
    session.close();

    // Using Hibernate
    session = sessionFactory.openSession();
    session.beginTransaction();
    queryStr = "select * from Events where EVENT_ID > 20 & EVENT_ID < 30";
    long start3 = System.currentTimeMillis();
    session.createSQLQuery(queryStr).list();
    long end3 = System.currentTimeMillis();
    long timeTaken3 = end3 - start3;
    System.out.println("Query took " + timeTaken3 + "ms");
    session.getTransaction().commit();
    session.close();

}
public void testBasicUsage(){
//使用JDBC
Session Session=sessionFactory.openSession();
session.beginTransaction();
字符串queryStr=“”;
试一试{
长启动=System.currentTimeMillis();
语句=((SessionImpl)session.connection().createStatement();
queryStr=“从事件ID<10”的事件中选择*;
ResultSet rs=语句.executeQuery(queryStr);
列表事件=新建ArrayList();
while(rs.next()){
Long eventId=rs.getLong(“事件ID”);
字符串标题=rs.getString(“标题”);
日期myDate=rs.getDate(“事件日期”);
事件=新事件(事件ID、标题、myDate);
事件。添加(事件);
}
long end=System.currentTimeMillis();
长时间=结束-开始;
System.out.println(“查询耗时”+耗时+“毫秒”);
}捕获(SQLE异常){
System.out.println(“语句创建错误”);
}
session.getTransaction().commit();
session.close();
//使用Hibernate
session=sessionFactory.openSession();
session.beginTransaction();
queryStr=“从事件ID>20和事件ID<30的事件中选择*”;
long start3=System.currentTimeMillis();
createSQLQuery(queryStr.list();
long-end3=System.currentTimeMillis();
长时间3=结束3-开始3;
System.out.println(“查询时间”+计时器3+“毫秒”);
session.getTransaction().commit();
session.close();
}

1:根据您的hibernate属性,hibernate将尝试重新创建数据库模式,这需要查询元数据、计算差异、应用差异(如果需要),而这不是在纯JDBC中完成的。任何比较都是无效的

2:多种技术之间的任何性能比较都需要一段预热期,因为有各种各样的幕后设置(连接到数据库、解析SQL语句、解释元数据等)。您还包括一个连接池大小,这取决于您使用hibernate的方式,可能会在以后给hibernate带来不公平的优势

3:您既没有包含Hibernate映射文件,也没有包含带有JPA注释的对象。即使这里的基本SQL语句没有连接,但如果您在对象中定义了关系,Hibernate也会考虑到这一点,所以再次强调,这可能不是一个公平的比较

4:在启动期间,Hibernate将连接到数据库,加载映射文件/对象,确保所有内容都对齐,并且数据库和持久性对象可用。如果您使用错误的语法、不正确的表/列名等命名查询,则应该对其进行标识。它还获取持久化对象,并执行一些动态字节生成/CGLIB操作,以使对象(至少在工作表下)不仅仅是一个普通的POJO(至少我们将其视为POJO)

5:当要求Hibernate获取数据时,它将创建SQL语句并将结果直接绑定到对象中。所以很明显,这会带来一些开销,但一旦完成,效率会更高。在直接的JDBC循环中,每次需要搜索以查找getLong、getString、getDate等返回的列,而不是只计算一次列号,然后使用直接索引。这里可能是罪魁祸首,Hibernate需要一点时间来有效地设置所有内容,然后由于创建对象的效率,最终超过了原始JDBC


6:作为一个抽象层,Hibernate总是比编写良好的直接JDBC应用程序(本例并非如此)慢。然而,开发时间更短,bug更少,代码的总体质量应该更好。你只需要在它的限制范围内工作。

我不知道为什么每件事都要加粗,很抱歉。谢谢你的回复。点1仅在应用程序启动时有效,因此不会影响查询时间。对于第3点,这里是我的类和映射文件,它没有任何关联。hibernate确实做了很多事情,比如在持久性上下文中保存对象,使用反射查找对象字段,等等。我想知道通过hibernate获得更少行(即10行)的时间分布。hibernate中的哪些构造使用了多少时间,因此即使对于较小的行,也需要300ms。获取同一组行以及不同组的10行、50行、100行组合。结果是一样的。每次在数据库中花费的测量时间不超过5毫秒。剩下的时间花在ORM上。我很想知道o情况下的时间分布