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

  我们大体了解,Spring框架是为了方便我们编程的。尤其是一些特别麻烦的初始化和结束过程。
  啥叫麻烦的初始化和结束过程?
  例如:之前写的 单独使用Hibernate不含SSH中SS的帖子
    1、先用configure()载入配置xml文件
    2、再获取StandardServiceRegistryB uilder类
    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
    private SessionFactory sessionFactory;
    //获取和当前线程绑定的Session
    private Session getSession(){
        return sessionFactory.getCurrentSession();
    }
    @Override public void saveBook(Book book){
        getSession().save(book);
    }
}
  十个步骤变成了2个步骤:
    5、最后获取Session
    8、用Session做 、删、改、查
  非常方便。
  但当我要实现用Session来删除一行时,却出现了问题。因为Spring终归是管理类的类工厂,你要是没指定它生产你想要的东西,那么它就不会在那里。我们重新看一下beans.xml文件:
<tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="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 Session found 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 for current 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(Native Method)
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(Unknown Source)
myController1.HiFirstApp.addNewWord(HiFirstApp.
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
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:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="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) {
        Session session=this.getSession();
        Word wd=(Word)session.load(Word.class, id);
        try{
            session.delete(wd);
        }catch(org.hibernate.ObjectNotFoundException e){
            return false;
        }
        return true;
    }

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




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值