环境
spring 3.2.3 RELEASE
spring data jpa 1.3.1.RELEASE
hibernate core 4.2.2.Final
问题
周末没事想把hibernate二级缓存监控集成到应用中,之前hibernate3.6的时候集成过(之前没用spring data jpa,所以怀疑是它的问题),不过为了和现有风格的统一,重新写了一遍,在写的过程中遇到一个问题:
hibernate Session打开的次数 比 Session关闭的次数 多很多次。而且这个比例是固定的,打开以前的hibernate3.6的发现没什么问题。打开和关闭次数是相等的才对。
经过源码跟踪,发现是spring data jpa,打开hibernate会话后没有关闭造成的。原因是spring data jpa在生成接口的QL时,需要去验证QL是否正确,此时它创建了Query但没有执行也没有释放造成的。
这是一个bug。已提交:https://jira.springsource.org/browse/DATAJPA-350
分析:
1、用过spring data jpa的朋友都应该知道,我们只需要写一些约定的接口并声称QL,或者在接口上使用如@Query指定QL,它能自动创建实现类并帮我们执行QL。此处不分析具体的步骤了。
2、在找到这些接口和@Qeury后,spring data jpa会验证这些QL是否正确。
3、最简单的是是使用SimpleQuery
org.springframework.data.jpa.repository.query.SimpleJpaQuery:
SimpleJpaQuery(JpaQueryMethod method, EntityManager em, String queryString) { …… // Try to create a Query object already to fail fast if (!method.isNativeQuery()) { try { em.createQuery(query.getQuery()); } catch (RuntimeException e) { // Needed as there's ambiguities in how an invalid query string shall be expressed by the persistence provider // http://java.net/projects/jpa-spec/lists/jsr338-experts/archive/2012-07/message/17 throw e instanceof IllegalArgumentException ? e : new IllegalArgumentException(e); } } …… }
大家已经注意到了,em.createQuery(query.getQuery()); 创建了Query 但没有执行,也没有关闭它。
4、因为我们spring data jpa 和spring集成了,所以注入的EntityManager是通过:
org.springframework.orm.jpa.SharedEntityManagerCreator创建的EntityManager代理对象;具体去参考源码;
5、当我们执行创建Query时:
// Regular EntityManager operations. boolean isNewEm = false; if (target == null) { logger.debug("Creating new EntityManager for shared EntityManager invocation"); target = (!CollectionUtils.isEmpty(this.properties) ? this.targetFactory.createEntityManager(this.properties) : this.targetFactory.createEntityManager()); isNewEm = true; } // Invoke method on current EntityManager. try { Object result = method.invoke(target, args); if (result instanceof Query) { Query query = (Query) result; if (isNewEm) { Class[] ifcs = ClassUtils.getAllInterfacesForClass(query.getClass(), this.proxyClassLoader); result = Proxy.newProxyInstance(this.proxyClassLoader, ifcs, new DeferredQueryInvocationHandler(query, target)); isNewEm = false; } else { EntityManagerFactoryUtils.applyTransactionTimeout(query, this.targetFactory); } } return result; } catch (InvocationTargetException ex) { throw ex.getTargetException(); } finally { if (isNewEm) { EntityManagerFactoryUtils.closeEntityManager(target); } }
此时大家注意到了,如果创建的是Query,isNewEm=false;而且Query也被代理了,那么finally不会关闭;
6、Query会执行完毕后执行关闭:
if (method.getName().equals("getResultList") || method.getName().equals("getSingleResult") || method.getName().equals("executeUpdate")) { EntityManagerFactoryUtils.closeEntityManager(this.em); }
7、问题就出在这,我们第【3】步创建了Query但没有执行,造成Session一直不释放,所以造成二级缓存查到的关闭的Session数量比打开的少很多。
解决方案:
自己获取EntityManager执行并关闭,这样就不会有问题了。
EntityManager target = null; // Try to create a Query object already to fail fast if (!method.isNativeQuery()) { try { target = em.getEntityManagerFactory().createEntityManager(); target.createQuery(query.getQuery()); } catch (RuntimeException e) { // Needed as there's ambiguities in how an invalid query string shall be expressed by the persistence provider // http://java.net/projects/jpa-spec/lists/jsr338-experts/archive/2012-07/message/17 throw e instanceof IllegalArgumentException ? e : new IllegalArgumentException(e); } finally { EntityManagerFactoryUtils.closeEntityManager(target); }
看了一下spring data jpa 1.4版本,没有修复,下午提交下bug。
另外使用hibernate 4做二级缓存监控的注意了:
hibernate4没有记录close Statement,即查看二级缓存的close Statement永远是0。也是个bug。
https://hibernate.atlassian.net/browse/HHH-8287
相关推荐
开发者可以通过 `EntityManager` 和 `EntityManagerFactory` 进行这些操作,但 Spring Data JPA 提供的 Repository 接口让这些操作更加简洁。 3. **Query Methods**:Spring Data JPA 支持通过方法名自动转换为 JPA...
Spring Data JPA API。 Spring Data JPA 开发文档。 官网 Spring Data JPA API。
例如,Spring Data JPA支持自动化的查询生成,只需定义Repository接口,无需编写任何实现代码,就可以执行CRUD(创建、读取、更新、删除)操作。此外,它还支持复杂的查询方法命名,如findByXXX,根据方法名自动构建...
Spring框架的核心特性包括依赖注入(DI)和面向切面编程(AOP),并且它还提供了对数据库操作的支持,这主要通过Spring Data JPA和Java Persistence API(JPA)实现。 Spring注解是Spring框架中的一大特色,它极大...
《Spring Data JPA从入门到精通》是一本深入解析Spring Data JPA的书籍,它以Spring Boot框架为核心,旨在帮助读者全面理解并熟练运用Spring Data JPA进行数据库操作。Spring Data JPA是Spring Framework的一个模块...
Spring Data JPA是Spring生态中的一个强大ORM框架,它极大地提高了Java开发者在处理数据库操作时的效率。Spring Data JPA的主要优点在于其高度的开发效率、成熟的语法结构以及与Spring框架的紧密集成。 1. **开发...
Spring Data JPA 是一个基于 Java 的开源框架,它属于 Spring Data 家族的一部分,旨在简化 Java 应用中的数据访问层代码,特别针对基于 JPA(Java Persistence API)的数据持久化操作。本教程将详细介绍 Spring ...
Spring Data JPA 是一个强大的框架,它简化了与Java Persistence API (JPA) 的交互,JPA 是Java 开发者用来管理和持久化应用程序数据的一种标准。在这个“Spring Data JPA Demo”项目中,我们将深入探讨如何利用...
**Spring Data JPA 深度解析** Spring Data JPA 是 Spring Framework 的一个重要模块,它为 Java ...掌握 Spring Data JPA 能够显著提高开发效率,降低数据访问层的复杂性,是现代 Java Web 开发不可或缺的一项技能。
SpringDataJPA是Spring框架中用于简化数据持久层操作的一个模块,它基于Java持久层API(Java Persistence API,JPA)...这样的特性,使得SpringDataJPA成为了Java开发者在进行数据持久化层开发时的一个非常重要的选择。
在本项目中,我们主要探讨如何手动构建一个基于SpringMVC、Spring Data JPA、Hibernate以及FreeMarker模板引擎的Maven工程,同时实现环境切换功能。这个基础框架为日常开发工作提供了必要的支持。 首先,SpringMVC...
Spring Data JPA是Java开发中的一个关键框架,它简化了与关系型数据库的交互,特别是基于Java Persistence API (JPA)。这个框架是Spring生态系统的组成部分,为开发者提供了声明式数据访问的方式,允许通过简单的...
Spring Boot简化了应用的初始搭建以及配置,而Spring Data JPA则是Spring Framework的一个模块,专门用于简化JPA(Java Persistence API)的使用,提供了一种声明式的方式来操作数据库。 首先,我们需要了解Spring ...
Spring Data JPA 提供了自动化的 CRUD 操作接口。创建一个继承自 `JpaRepository` 的接口,例如 `UserRepository.java`: ```java import org.springframework.data.jpa.repository.JpaRepository; public ...
在使用Spring Data JPA时,开发者无需编写大量的DAO(Data Access Object)层代码,只需要定义Repository接口,Spring Data JPA就会自动生成实现。这极大地提高了开发效率和代码的可维护性。此外,通过集成Spring,...
在现代Java Web开发中,Spring Boot框架以其便捷的配置、快速的应用启动以及强大的依赖管理而备受推崇。...通过灵活的配置和强大的功能,Spring Data JPA成为Java开发者在处理数据持久化时的首选工具。
标题"其实spring data jpa比mybatis更好用.zip_JPA mybatis"指出本主题将探讨Spring Data JPA与MyBatis之间的比较,并暗示在某些方面,Spring Data JPA可能更为优越。描述中提到"全方位介绍jpa",表明内容将深入讲解...
Spring Data JPA是Spring框架的一个模块,主要目的是简化Java企业级应用中数据访问层的开发。这个框架构建在JPA(Java Persistence API)之上,提供了一种声明式的方式来操作数据库,使得开发者无需编写大量的SQL...