环境
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
相关推荐
Spring Data JPA API。 Spring Data JPA 开发文档。 官网 Spring Data JPA API。
Spring Data JPA中文文档1.4.3
'SpringDataJPA从入门到精通'分为12章 内容包括整体认识JPA、JPA基础查询方法、定义查询方法、注解式查询方法、@Entity实例里面常用注解详解、JpaRepository扩展详解、JPA的MVC扩展REST支持、DataSource的配置、乐观...
spring注解完整版+spring data jpa官方文档中文翻译+JPA2.0官方文档 文档内容齐全 值得参考学习
spring data jpa最新版本1.8.0,包含了spring-data-jpa-1.8.0.RELEASE.jar,spring-data-jpa-1.8.0.RELEASE-javadoc.jar以及 spring-data-jpa-1.8.0.RELEASE-sources.jar文档和源代码
使用 SpringBoot + SpringDataJPa 设计通用的权限管理系统,适合管理系统快速开发迭代,可用于开发模板,项目经过测试,可完美运行! 使用 SpringBoot + SpringDataJPa 设计通用的权限管理系统,适合管理系统快速...
声明:该应用仅仅是技术研究:Spring Data JPA的配置和常见api的使用&maven构建项目,其他技术不在此研究 内涵sql和各种Spring Data JPA测试和案例,导入&创建DB,配置好maven便可运行 maven构建项目&问题:...
仓库管理系统,SpringBoot+Spring Data JPA.zip仓库管理系统,SpringBoot+Spring Data JPA.zip仓库管理系统,SpringBoot+Spring Data JPA.zip仓库管理系统,SpringBoot+Spring Data JPA.zip仓库管理系统,SpringBoot...
Spring Data JPA Demo
NULL 博文链接:https://mixo44.iteye.com/blog/1797079
Spring Data JPA是Spring基于Hibernate开发的一个JPA框架。如果用过Hibernate或者MyBatis的话,就会知道对象关系映射(ORM)框架有多么方便。但是Spring Data JPA框架功能更进一步,为我们做了 一个数据持久层框架...
Spring Data JPA中文文档[1.4.3].zip
3. 与Spring全家桶结合紧密: 4. 成熟的框架和架构 常⻅的SQL性能问题,如何优雅处理? 2. 错综复杂的关联关系如何应对? 3. 万恶的LazyException本质是什么? 4. ⾼并发⾼性能要求的API服务要⽤JPA吗?
第一章:Spring Data JPA入门 包括:是什么、能干什么、有什么、HelloWorld等 第二章:JpaRepository基本功能 包括:代码示例JpaRepository提供的CRUD功能,还有翻页、排序等功能 第三章:JpaRepository的查询 ...
该案例使用SpringBoot 整合了SPringData JPA,使用SpringData 开发简化了Dao层的开发量,简化了数据访问,使得持久化更加简单 !
Spring Data JPA 是 Spring 基于 ORM 框架、JPA 规范的基础上封 装的一套 JPA 应用框架,可使开发者用极简的代码即可实现对数据库 的访问和操作。它提供了包括增删改查等在内的常用功能,且易于扩 展!学习并使用 ...
基于SpringBoot+Spring Data JPA+mybatis的仓库管理系统 基于SpringBoot+Spring Data JPA+mybatis的仓库管理系统 基于SpringBoot+Spring Data JPA+mybatis的仓库管理系统 基于SpringBoot+Spring Data JPA+mybatis的...
Maven整合Spring+SpringMVC+Hibernate+SpringDataJPA
Spring Data JPA中文文档[1.4.3] Spring Data JPA中文文档[1.4.3]