好久的笔记了,趁刚好休息整理文档,翻出这一部分,稍加整理后,就发上来给大家共享一下,希望对各位有所帮助。
关于LazyLoadException异常,使用过Hibernate O/R Mapping工具的人应该都遇到过,网上也是有很多解决的方案,其中Spring提供的一个方案就是在web.xml增加一个filter,示例代码如下:
<filter>
<filter-name>entityManager</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>entityManagerFilter</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>
解决办法有了,接下来应该会有人好奇:这个配置filter后它是如何工作的?
下面来分析一下这个功能实现的源代码, 不过之前,比较重要的是了解,为何会出现lazyload exception的异常发生。
下面我模拟写了一段代码,这段代码就会发生该异常
注:只是为了说明,相关的代码就省略了。
@Entity
public class Room {
@Id
@Column(length=32)
private String id;
@Column(length=20)
private code;
@OneToMany(mappedBy="room") //default is use lazy load strategy
private Set desks;
}
@Entity
public class Desk {
@Id
@Column(length=32)
private String id;
@Column(length=20)
private code;
@ManyToOne
private Room root;
}
public class RoomSerivce {
@Transactional(readOnly=true)
public Room getRoomById(String roomId) {
Assert.notBlank(roomId, "room'id is null);
return getDao().findById(roomId);
}
}
1 public class RoomServiceTest {
2
3 public static void main(String[] args[]) {
4
5 //get service from spring beanfactory
6 RoomService service = SpringContext.getSerivce("roomService");
7 Assert.notNull(service, " roomService bean not exsit");
8
9 Room room = service.getRoomById("1");
10 //here lazy exception throw out
11 Set Desks = room.getDesks();
12 CollectionsUtils.toString(Desks);
13 }
14 }
分析这段代码,我们不难发现,在RoomServiceTest这个测试的例子中,因为使用了基于Annotation的声明性事务,所以在 RoomSerivce.getRoomById方法运行结束后,事务就已经提交了。但示例中Room实体与Desk实例的关系使用的是lazy fetch的策略,此时Room对象中的desks集合还是为空。
当执行到下面两句时(这才真正使用到desks集合时)
Set Desks = room.getDesks();
CollectionsUtils.toString(Desks);
Hibernate就会根据原来lazy设定的方式,取EntityManager, 根据它从数据库查询 Desk实现的数据,这时上面我们已经提到,事务已经随getRoomById方法的运行结束提交. EntityManager对象也已经关闭。此时再调用 EntityManager操作,就会报EntityManager has been closed 异常(lazy load exception)
ok, 清楚这块,大家有时可能也猜想到了Spring这个解决方案是怎么处理的了。
Spring的TransactionInterceptor 其就是通过AOP负责拦截着所有针对事务TransactionManager的操作.
这样Spring就可以针对lazy异常进行拦截了。
清楚上面的后,下面的代码是非常好理解了,来看一下OpenEntityManagerInViewFilter的代码:
我加了些注释,大家很容易明白:
protected void doFilterInternal(
2 HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
3 throws ServletException, IOException {
4
5 //通过WebApplicationContext,从Web服务中取得context实例后,根据EntityManagerFactory.class类型
6 //取得EntityManagerFacotry实例
7 EntityManagerFactory emf = lookupEntityManagerFactory(request);
8 boolean participate = false;
9
10 //如果静态方法hasResource已经有EntityManagerFactory实例了,就不用再通过
11 //EntityManagerFactory创建一个新EntityManger了
12 if (TransactionSynchronizationManager.hasResource(emf)) {
13 // Do not modify the EntityManager: just set the participate flag.
14 participate = true;
15 }
16 else {
17 logger.debug("Opening JPA EntityManager in OpenEntityManagerInViewFilter");
18 try {
19 //通过EntityManagerFactory创建一个新EntityManger,并通过bindResource方法
20 //保存到TransactionSynchronizationManager中
21 //这样,通TransactionSynchronizationManager的getResource方法取得EntityMangerHolder
22 EntityManager em = createEntityManager(emf);
23 TransactionSynchronizationManager.bindResource(emf, new EntityManagerHolder(em));
24 }
25 catch (PersistenceException ex) {
26 throw new DataAccessResourceFailureException("Could not create JPA EntityManager", ex);
27 }
28 }
29
30 try {
31 filterChain.doFilter(request, response);
32 }
33
34 finally {
35 if (!participate) {
36 //每次请求结束后,就把EntityManager关闭
37 EntityManagerHolder emHolder = (EntityManagerHolder)
38 TransactionSynchronizationManager.unbindResource(emf);
39 logger.debug("Closing JPA EntityManager in OpenEntityManagerInViewFilter");
40 EntityManagerFactoryUtils.closeEntityManager(emHolder.getEntityManager());
41 }
42 }
43 }
上面的代码就不用多解释了, 到现在已经很清楚知道Spring针对 Hibernate的Lazy问题是怎么解决的。
当然我们可以扩展到除Web服务以外,来实现解决lazy的问题。(我们自己来管理TransactionSynchronizationManager就可以了)
当然Spring针对 Hibernate(非JPA的实现)原理也是一样,只是它针对的SessionFactory,也是由TransactionSynchronizationManager来统一管理。
最后如果大家如还有不清楚的,欢迎一起讨论。
Good Luck!
Yours Matthew!
分享到:
相关推荐
这个“Spring+hibernate整合源代码”应该包含了实现上述整合步骤的示例代码,可以作为学习和参考的资源。通过学习和实践这些代码,你可以更好地理解和掌握 Spring 和 Hibernate 整合的细节,提升你的 Java Web 开发...
在本项目中,我们主要探讨如何手动构建一个基于SpringMVC、Spring Data JPA、Hibernate以及FreeMarker模板引擎的Maven工程,同时实现环境切换功能。这个基础框架为日常开发工作提供了必要的支持。 首先,SpringMVC...
在IT行业中,构建一个基于Spring、SpringMVC、Hibernate和JPA的开发环境是常见的任务,这四个组件都是Java企业级应用开发中的重要工具。让我们深入探讨这些技术以及如何将它们整合在一起搭建一个完整的开发环境。 *...
**SessionFactory的创建**:Spring管理SessionFactory,通常在ApplicationContext.xml中配置,通过`<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">`指定数据源、...
在实际项目中,集成Spring、JPA和Hibernate时,开发者需要配置Spring的XML或Java配置文件,声明数据源、事务管理器以及JPA的实体扫描路径。同时,还需要配置Hibernate的相关属性,比如连接池、方言等。此外,可能还...
总结来说,"Spring+SpringMVC+SpringDataJPA+Hibernate"组合为Java开发提供了一个强大且灵活的工具集,使得开发人员可以高效地构建复杂的Web应用程序,同时保持代码的整洁和可维护性。通过这个集成框架,我们可以...
标题 "Spring+Hibernate+Jpa+Struts2整合实例" 描述的是一个综合性的Web开发教程,它将四个关键的Java技术框架集成在一起,用于构建高效的企业级应用程序。这个实例涵盖了Spring作为整体应用的管理框架,Hibernate...
在IT行业中,构建高效、可维护的Web应用是至关重要的,而"Maven+SpringMVC+SpringJPA+Hibernate"的组合就是一个常见的解决方案。这个组合提供了全面的开发工具和技术,帮助开发者快速构建基于Java的Web应用程序。...
在"maven+springjpa+hibernate"的例子中,Maven用于管理项目依赖,包括Spring Data JPA和Hibernate库。 **Spring Data JPA** Spring Data JPA是Spring框架的一部分,它简化了JPA(Java Persistence API)的使用,...
在这个"Spring+SpringMVC+SpringData+JPA+Hibernate+Shiro"的组合中,我们涉及到了Spring生态系统的多个核心组件,以及两个重要的持久层技术和一个安全框架。下面将逐一详细介绍这些技术及其整合方式。 1. **Spring...
1、本示例只是借花献佛,其实网上SpringMVC+Hibernate-JPA的示例代码一大堆,但是有源代码的demo很少,而且大部分介绍不全面,容易造成学习误区。我也是曾经学习网上示例来完成这个demo。本人是参考...
【标题】"java+Spring+Hibernate整合的企业OA源码"所代表的是一个使用Java编程语言,结合Spring框架和Hibernate持久层框架实现的企业级办公自动化(Office Automation,简称OA)系统的源代码。这样的系统通常用于...
在IT行业中,Spring和Hibernate是两个非常重要的框架,它们分别在应用层和数据持久化层发挥着关键作用。Spring是一个全面的Java企业级应用开发框架,而Hibernate则是一个优秀的对象关系映射(ORM)工具,它简化了...
在ODshop这个项目中,我们可能可以看到如何在Spring和Hibernate集成的环境中设置事务,包括如何配置DataSource、SessionFactory、HibernateTemplate或JPA的EntityManagerFactory,以及如何处理事务的回滚和提交。...
- `src` 存放源代码,包括Java类和资源文件。 - `resources` 通常存放配置文件,如Spring的配置文件、Hibernate的映射文件等。 - `build` 文件夹是编译后的输出目录。 - `.settings` 包含项目的Eclipse特定设置...
1. **配置文件**:设置SpringMVC、Hibernate JPA和Spring Data JPA的相关配置,如数据源、实体扫描路径、JPA配置等。 2. **实体类**:定义与数据库表对应的实体类,包含属性和注解。 3. **Repository接口**:定义...
在Spring与Hibernate的整合中,Spring的DataSource、SessionFactory和HibernateTemplate或JPA的EntityManagerFactory等关键组件可以通过注解@Configuration和@Bean来配置。比如,我们可以使用@...
在 `Meerkat-WEB` 文件中,我们可以期待找到项目的源代码结构,包括配置文件、Java 类(如 Controller、Service、Repository 等)、视图模板(可能是 Thymeleaf 或 JSP),以及可能的测试类。项目可能还包含数据库...
8. **Spring 的 AOP**:AOP 提供了一种面向切面的编程方式,可以在不修改源代码的情况下,对特定关注点(如日志、事务)进行横切关注。在 Spring+Hibernate 中,AOP 可用于事务的自动管理。 9. **JPA(Java ...
在"Maven整合Spring+SpringMVC+Hibernate+SpringDataJPA+JdbcTemplate"的DEMO中,开发者通常会创建一个Maven工程,配置相关依赖,然后分别设置Spring的配置文件(如`applicationContext.xml`)、SpringMVC的配置文件...