正确使用Spring MVC 3和Hibernate(Spring ORM)


问题内容

我正在开始一个新项目,这次尝试做正确的事情(所以不止一个问题),我可能需要一些帮助,但不确定自己做错了什么:

  1. Spring context
  2. Controller
  3. Service Interface
  4. Service Implementation
  5. DAO interface
  6. DAO implementation

我想尽可能多地利用spring MVC,如何通过@Transactional处理会话打开/关闭?

如何捕获异常(即不存在的记录或数据库失败)(如果有)。即我的数据库不接受像这样的重复条目:

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry

我怎样才能抓住这个?

对于每个下一个请求,我都会收到此异常:

org.hibernate.AssertionFailure: null id in com.test.spring.ws.service.impl.TestObject entry (don't flush the Session after an exception occurs)

我做错了什么?有人可以建议我的项目做些改进吗?


问题答案:

组件扫描

首先,首先要使用的是@ Controller,@ Service,@
Repository和@Autowired,但是您对它们不做任何事情。我建议使用类路径扫描。从您的spring上下文文件中删除“ testServiceDAO”和“ testService” bean,而使用:

<context:component-scan base-package="com.test.spring.ws"/>

这将通过它们的注释查找并创建那些bean,而不是要求您在XML中声明它们。将@Autowired添加到testServiceDAO服务中的sessionFactory字段和DAO中的字段。删除这些字段的设置器。不再需要它们。component-
scan标签也将为您自动布线。要使用context命名空间,您需要将其添加到根元素中。例如:

<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:context="http://www.springframework.org/schema/context"
     xsi:schemaLocation="
         http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
         http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context-3.0.xsd">

交易管理

如Sean所说,要使用@Transactional,您需要在spring上下文文件中添加一个元素:

<tx:annotation-driven/>

由于您的事务管理器Bean被命名为“ transactionManager”,它将自动找到它。您还需要在根元素中添加“ tx”命名空间,因此其外观应类似于:

<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:context="http://www.springframework.org/schema/context"
     xmlns:tx="http://www.springframework.org/schema/tx"
     xsi:schemaLocation="
         http://www.springframework.org/schema/beans 
         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
         http://www.springframework.org/schema/tx 
         http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
         http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context-3.0.xsd">

为了使这种方法有可能工作,您需要同时从DAO方法中删除session.beginTransaction()和两者session.close()。以这种方式打开您自己的事务是将编程性和声明性事务划分混合在一起,并且声明性方法通常更好。另外,您永远
不要在实际项目中的DAO中关闭会话。那会让您陷入各种麻烦。

异常处理

MySQLIntegrityConstraintViolationException是特定于数据库的异常,将被Hibernate捕获并包装在ConstraintViolationException中,这是从您的DAO中得出的结果;但是,由于您的DAO现在是@Repository,因此您可以从Spring的异常翻译中受益。这样,Spring将捕获Hibernate异常并将其转换为DataIntegrityViolationException。数据库异常处理总是很有趣!

会话管理

您是否正在使用OpenSessionInViewFilterOpenSessionInViewInterceptor?如果是这样,则在首次接收到请求时将打开hibernate会话,并在写入响应后将其关闭。如果不是,则会话直到事务开始(通过@Transactional方法)后才开始,并且在事务完成时关闭。使用过滤器/拦截器,您可以在“视图”层中完成需要回调数据库的操作-
特别是当您具有呈现视图所需的惰性关系或延迟加载的对象时。如果会话不可用-如果会话仅存在于事务服务方法的长度范围内则不存在-
您无法在视图中执行这些操作,并且

至于出现的“不要在异常发生后刷新会话”错误,我看不到任何立即使我认为应该发生的事情。可能是您的Web层Spring上下文中的某些内容配置错误,或者直接在DAO中处理事务和会话的方式存在一些奇怪的相互作用。