你可以在JPQL查询中使用标准函数,就像在SQL查询中调用它们一样。你只需引用该函数的名称,后跟一个左括号,一个可选的参数列表和一个右括号。
Query q = em.createQuery("SELECT a, size(a.books) FROM Author a GROUP BY a.id");
List<Object[]> results = q.getResultList();
并且,通过JPA的函数function,你也可以调用数据库特定的或自定义的数据库函数。
TypedQuery<Book> q = em.createQuery( "SELECT b FROM Book b WHERE b.id = function('calculate', 1, 2)", Book.class);Book b = q.getSingleResult();
错误7:无理由地调用flush方法
这是另一个比较普遍的错误。开发人员在持久化一个新实体或更新现有实体后,调用EntityManager的flush方法时经常会出现这个错误。这迫使Hibernate对所有被管理的实体执行脏检查,并为所有未决的插入、更新或删除操作创建和执行SQL语句。这会减慢应用程序,因为它阻止了Hibernate使用一些内部优化。
Hibernate将所有被管理的实体存储在持久性上下文中,并试图尽可能延迟写操作的执行。这允许Hibernate将同一实体上的多个更新操作合并为一个SQL UPDATE语句,通过JDBC批处理绑定多个相同的SQL语句,并避免执行重复的SQL语句,这些SQL语句返回你已在当前Session中使用的实体。
作为一个经验法则,你应该避免任何对flush方法的调用。JPQL批量操作是罕见的例外之一,对此我将在错误9中解释。
错误8:使用Hibernate应付一切
Hibernate的对象关系映射和各种性能优化使大多数CRUD用例的实现非常简单和高效。这使得Hibernate成为许多项目的一个很好的选择。但这并不意味着Hibernate对于所有的项目都是一个很好的解决方案。
我在我之前的一个帖子和视频中详细讨论过这个问题。JPA和Hibernate为大多数创建、读取或更新一些数据库记录的标准CRUD用例提供了很好的支持。对于这些用例,对象关系映射可以大大提升生产力,Hibernate的内部优化提供了一个很优越的性能。
但是,当你需要执行非常复杂的查询、实施分析或报告用例或对大量记录执行写操作时,结果就不同了。所有这些情况都不适合JPA和Hibernate的查询能力以及基于实体管理的生命周期。
如果这些用例只占应用程序的一小部分,那么你仍然可以使用Hibernate。但总的来说,你应该看看其他的框架,比如jOOQ或者Querydsl,它们更接近于SQL,并且可以避免任何对象关系映射。
错误9:逐个更新或删除巨大的实体列表
在你看着你的Java代码时,感觉逐个地更新或删除实体也可以接受。这就是我们对待对象的方式,对吧?
这可能是处理Java对象的标准方法,但如果你需要更新大量的数据库记录,那么,这就不是一个好方法了。在SQL中,你只需一次定义一个影响多个记录的UPDATE或DELETE语句。数据库将会非常高效地处理这些操作。
不幸的是,用JPA和Hibernate操作起来则没有那么容易。每个实体都有自己的生命周期,而你如果要更新或删除多个实体的话,则首先需要从数据库加载它们。然后在每个实体上执行操作,Hibernate将为每个实体生成所需的SQL UPDATE或DELETE语句。因此,Hibernate不会只用1条语句来更新1000条数据库记录,而是至少会执行1001条语句。
很显然,执行1001条语句比仅仅执行1条语句需要花费更多的时间。幸运的是,你可以使用JPQL、原生SQL或Criteria查询对JPA和Hibernate执行相同的操作。
但是它有一些你应该知道的副作用。在数据库中执行更新或删除操作时,将不使用实体。这提供了更佳的性能,但它同时忽略了实体生命周期,并且Hibernate不能更新任何缓存。
在《How to use native queries to perform bulk updates》一文中对此我有一个详细的解释。
简而言之,在执行批量更新之前,你不应使用任何生命周期侦听器以及在EntityManager上调用flush和clear方法。flush方法将强制Hibernate在clear方法从当前持久化上下文中分离所有实体之前,将所有待处理的更改写入数据库。
em.flush();
em.clear();
Query query = em.createQuery("UPDATE Book b SET b.price = b.price*1.1");
query.executeUpdate();
错误10:使用实体进行只读操作
JPA和Hibernate支持一些不同的projections。如果你想优化你的应用程序的性能,那么你应该使用projections。最明显的原因是你应该只选择用例中需要的数据。
但这不是唯一的原因。正如我在最近的测试中显示的那样,即使你读取了相同的数据库列,DTO projections也比实体快得多。
在SELECT子句中使用构造函数表达式而不是实体只是一个小小的改变。但在我的测试中,DTO projections比实体快40%。当然,两者比较的数值取决于你的用例,而且你也不应该通过这样一个简单而有效的方式来提高性能。
优质内容筛选与推荐>>
1、getJSON回调函数不执行问题?2、关于 placeholder 在 360chrome 下的兼容性问题记录3、java基础(IO流)4、[转] 如何时刻保持最佳状态?12招!5、python 打包