SSH中操作Hibernate的事务与删除数…

来源:互联网 发布:青岛软件评测中心 编辑:程序博客网 时间:2024/05/16 12:26
  我们大体了解,Spring框架是为了方便我们编程的。尤其是一些特别麻烦的初始化和结束过程。
  啥叫麻烦的初始化和结束过程?
  例如:之前写的单独使用Hibernate不含SSH中SS的帖子里
    1、先用configure()载入配置xml文件
    2、再获取StandardServiceRegistryBuilder类
    3、然后获取ServiceRegistry
    4、然后得到SessionFactory
    5、最后获取Session
    6、还没完,借着开Transaction
…… ……才能开始干活。干活的过程如下:
    7、beginTransaction
    8、用Session做增、删、改、查
    9-1、没毛病的话,Transaction就提交更改
    9-2、有毛病的话,Transaction就rollback(回滚)
    10、最后session.close()
  于是最蛋碎的地方在于,只有红色那一条才是我们想做的事情,其他的9条(9-1、9-2算1条)全部都是不管怎么样都必须做的事情。所以我们需要Spring来做前处理和后处理,使用AOP功能对专门操作Session的方法进行拦截,做完前处理再执行,执行完还得做后处理。最后的结果就是在SH这个两框架整合的帖子中,保存这一功能被简化到这样:
@Repository
public class BookDaoImpl implements BookDao{
    @Autowired
    privateSessionFactory sessionFactory;
    //获取和当前线程绑定的Session
    privateSession getSession(){
        returnsessionFactory.getCurrentSession();
    }
    @Override publicvoid saveBook(Book book){
        getSession().save(book);
    }
}
  十个步骤变成了2个步骤:
    5、最后获取Session
    8、用Session做、删、改、查
  非常方便。
  但当我要实现用Session来删除一行时,却出现了问题。因为Spring终归是管理类的类工厂,你要是没指定它生产你想要的东西,那么它就不会在那里。我们重新看一下beans.xml文件:
<tx:adviceid="txAdvice"transaction-manager="transactionManager">
      <tx:attributes>
          <tx:methodname="get*"read-only="true"/>
      </tx:attributes>
</tx:advice>

  发现里面只定义了get方法需要用到Transaction,却没有定义其他方法。所以导致删除的时候出现了Exception(异常):
org.springframework.web.util.NestedServletException:Request processing failed; nested exception is org.hibernate.HibernateException: No Sessionfound for current thread
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.
root cause

org.hibernate.HibernateException: No Session found forcurrent thread
org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.
org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.
dao_service.WordBOImpl.getSession(WordBOImpl.
dao_service.WordBOImpl.deleteById(WordBOImpl.
sun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethod)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.
org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.
org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.
org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.
org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.
org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.
com.sun.proxy.$Proxy194.deleteById(UnknownSource)
myController1.HiFirstApp.addNewWord(HiFirstApp.
sun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethod)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.
org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.

  我们当然得添加其它方法的Transaction切点,方便Spring切到里面来,然后帮我们做前、后处理。根据最原始的Hibernate编程得知,在提交事务失败以后,需要回滚(相当于对数据修改前的还原点)。同样可以在xml文件里面声明。这里接着之前做过的SSH框架,在beans.xml文件里面更改:
 <tx:adviceid="txAdvice"transaction-manager="transactionManager">
      <tx:attributes>
          <tx:methodname="get*"read-only="true"/>
          <tx:methodname="delete*"propagation="REQUIRED"rollback-for="exception"/>
      </tx:attributes>
</tx:advice>
  
  我们很容易看出,delete加个*(星号)是一个正则表达式匹配,也就是我们在WordBOImpl.java里面写的代码,无论是deleteById,还是deleteByName,只要是delete开头的,都会给它匹配一个Transaction(事务)。然后当修改失败后,我们也能看到xml定义了rollback-for方法,当出现exception的时候就回滚。
  这是典型的AOP(面向切面)编程。
  于是以下的代码才能够顺利在SSH里面运行:
   @Override
   public boolean deleteById(int id) {
       Sessionsession=this.getSession();
       Wordwd=(Word)session.load(Word.class, id);
      try{
         session.delete(wd);
      }catch(org.hibernate.ObjectNotFoundException e){
          return false;
      }
       returntrue;
   }

后记:ObjectNotFoundException的问题
我试验过以下代码:
   @Override
   public boolean deleteById(int id) {
       Sessionsession=this.getSession();
       Wordwd;
       Objectobj=session.load(Word.class, id);
      System.out.println(obj.getClass().toString());
      System.out.println("isWord=="+(obj instanceof Word));
      wd=(Word)obj;
      if(wd==null){
         System.out.println("wd==null");
          return false;
       } else{
         System.out.println("wd!=null");
         System.out.println(wd.getId());
          System.out.println(wd.getKey());  //这里会出ObjectNotFoundException
          try {
             session.delete(wd);
          } catch(org.hibernate.ObjectNotFoundException e) {
             return false;
          }
      }
      
       returntrue;
   }
  这个问题发生在“MySQL那个表里面没这个id,你却硬要删除以此id开始的那一行”的情况。
  但有趣的事情是这个Object NotFound并不是空指针错误,session.load还真真切切把这个Word给load出来了,而且你用getID方法也不会出错,返回的确实是你要查询的那个ID。问题在于除了ID,别的啥都没有。这个Word类已经被改造过了,使用任何除查询ID以外的方法,都会报这个ObjectNotFoundException。看来Spring的工厂类不是盖的,的确将我们的Word改造了。
  于是干脆在删除的时候try一下,这样比较好。就像之前的一样,简洁大方:
   @Override
   public boolean deleteById(int id) {
       Sessionsession=this.getSession();
       Wordwd=(Word)session.load(Word.class, id);
      try{
         session.delete(wd);
      }catch(org.hibernate.ObjectNotFoundException e){
          returnfalse;
      }
       returntrue;
   }




0 0