使用hibernate正确使用Spring mvc 3(Spring ORM)

时间:2011-07-15 15:49:34

标签: java hibernate spring spring-mvc

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

  1. Spring context
  2. Controller
  3. Service Interface
  4. Service Implementation
  5. DAO interface
  6. DAO implementation
  7. 我想尽可能多地利用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)
    

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

4 个答案:

答案 0 :(得分:12)

组件扫描

首先要做的事情是:你正在使用@ Controller,@ Service,@ Repository和@Autowired,但是你没有对它们做任何事情。我建议使用classpath scanning。从spring上下文文件中删除“testServiceDAO”和“testService”bean,改为使用:

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

这将通过注释找到并创建这些bean,而不是要求您在XML中声明它们。将@Autowired添加到服务中的testServiceDAO字段以及DAO中的sessionFactory字段。删除这些字段的setter。他们不再需要了。组件扫描标签也将为您进行自动装配。要使用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">

交易管理

对于use @Transactional,正如肖恩所说,你需要在弹簧上下文文件中添加一个元素:

<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的exception translation中受益。有了这个,Hibernate异常将被Spring捕获并转换为DataIntegrityViolationException。数据库异常处理总是很有趣!

会话管理

您使用的是OpenSessionInViewFilter还是OpenSessionInViewInterceptor?如果是,则在首次接收请求时打开Hibernate会话,并在写入响应后关闭。如果没有,则会话直到事务开始(在@Transactional方法)才开始,并且在该事务完成时关闭。使用过滤器/拦截器,您可以在需要回调数据库的“视图”层中执行操作 - 特别是当您具有渲染视图所需的延迟关系或延迟加载对象时。如果会话不可用 - 因为它不是仅存在于事务服务方法的长度 - 你不能在视图中执行这些操作而你会得到臭名昭着的LazyInitializationException

至于“在发生异常后不刷新会话”错误,我得到的错误,我没有立即看到任何会让我觉得应该发生的事情。您的Web层Spring环境中的某些内容可能是配置错误,或者您在DAO中直接处理事务和会话时可能存在一些奇怪的相互作用。

答案 1 :(得分:2)

  

如何通过@Transactional处理会话开启/关闭?

您需要在弹簧上下文中使用<tx:annotation-driven />(和tx命名空间)。

(见Using @Transactional

答案 2 :(得分:1)

我建议扩展HibernateDaoSupport并使用HibernateTemplate而不是在DAO代码中明确使用SessionFactory(和创建事务)。

答案 3 :(得分:-1)

强烈建议远离春天的@Transactional。对于您的使用,请坚持使用open-session-in-view模式。当请求进入时,会话打开并启动事务。如果遇到异常或其他错误,请回滚事务。否则提交。这样,Hibernate就会为你解决所有繁重的工作。

如果沿着@Transactional的路走下去,当你试图理清从哪里来的时候,你将进入一个懒惰加载异常和其他奇怪行为的阴暗境界。在最坏的情况下,您需要仔细跟踪调用方法的顺序(即严格关注您的堆栈),以确保您拥有正确的权限。

最糟糕的是,如果你把@Transactional放在已经存在于Hibernate一级或二级缓存中的东西上,你将会得到很多很多BEGIN / END事务进入你的数据库而没有执行实际的查询(因为它们在缓存中。这可能会破坏你的表现,而且几乎不可能撤销。

会话中的事务爆发后,您需要回滚。您可能需要重做会话,具体取决于周围的语义。第一个修复很简单 - 在执行保存之前首先检查实体是否已存在。这将解决第二个问题。

查看此article comparing Hibernate/JPA and myBatis以获取更多评论。