何时使用Entity或DTO (3)

JPA和Hibernate支持一组查询提示(hits),允许你提供有关查询及其执行方式的其他信息。查询提示QueryHints.HINT_READONLY告诉Hibernate以只读模式查询实体。因此,Hibernate不需要对它们执行任何脏检查,也可以应用其他优化。

你可以通过在Query接口上调用setHint方法来设置此提示。

long timeTx = 0; long timeQuery = 0; long iterations = 1000; // Perform 1000 iterations for (int i = 0; i < iterations; i++) {     EntityManager em = emf.createEntityManager();     long startTx = System.currentTimeMillis();     em.getTransaction().begin();     // Execute Query     long startQuery = System.currentTimeMillis();     Query query = em.createQuery("SELECT b FROM Book b");     query.setHint(QueryHints.HINT_READONLY, true);     query.getResultList();     long endQuery = System.currentTimeMillis();     timeQuery += endQuery - startQuery;     em.getTransaction().commit();     long endTx = System.currentTimeMillis();     em.close();     timeTx += endTx - startTx; } System.out.println("Transaction: total " + timeTx + " per iteration " + timeTx / (double)iterations); System.out.println("Query: total " + timeQuery + " per iteration " + timeQuery / (double)iterations);

你可能希望将查询设置为只读来让性能显著的提升——Hibernate执行了更少的工作,因此应该更快。

但正如你在下面看到的,执行时间几乎与之前的测试相同。至少在此测试场景中,将QueryHints.HINT_READONLY设置为true不会提高性能。

Transaction: total 2842 per iteration 2.842 Query: total 2006 per iteration 2.006 3.6.查询DTO

加载100 本书实体大约需要2ms。让我们看看在JPQL查询中使用构造函数表达式获取相同的数据是否表现更好。

当然,你也可以在Criteria查询中使用构造函数表达式。

long timeTx = 0; long timeQuery = 0; long iterations = 1000; // Perform 1000 iterations for (int i = 0; i < iterations; i++) {     EntityManager em = emf.createEntityManager();     long startTx = System.currentTimeMillis();     em.getTransaction().begin();     // Execute the query     long startQuery = System.currentTimeMillis();     List<BookValue> books = em.createQuery("SELECT new org.thoughts.on.java.model.BookValue(b.id, b.title) FROM Book b").getResultList();     long endQuery = System.currentTimeMillis();     timeQuery += endQuery - startQuery;     em.getTransaction().commit();     long endTx = System.currentTimeMillis();     em.close();     timeTx += endTx - startTx; } System.out.println("Transaction: total " + timeTx + " per iteration " + timeTx / (double)iterations); System.out.println("Query: total " + timeQuery + " per iteration " + timeQuery / (double)iterations);

正如所料,DTO投影比实体(Entity)投影表现更好。

Transaction: total 1678 per iteration 1.678 Query: total 1143 per iteration 1.143

平均而言,执行查询需要1.143ms,执行事务需要1.678ms。查询的性能提升43%,事务的性能提高约42%。

对于一个花费一分钟实现的小改动而言,这已经很不错了。

在大多数项目中,DTO投影的性能提升将更高。它允许你选择用例所需的数据,而不仅仅是实体映射的所有属性。选择较少的数据几乎总能带来更好的性能。

4.摘要

为你的用例选择正确的投影比你想象的更容易也更重要。

如果要实现写入操作,则应使用实体(Entity)作为投影。Hibernate将管理其状态,你只需在业务逻辑中更新其属性。然后Hibernate会处理剩下的事情。

你已经看到了我的小型性能测试的结果。我的笔记本电脑可能不是运行这些测试的最佳环境,它肯定比生产环境慢。但是性能的提升是如此之大,很明显你应该使用哪种投影。

file

 

使用DTO投影的查询比选择实体的查询快约40%。因此,最好花费额外的精力为你的只读操作创建DTO并将其用作投影。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpyxgx.html