我们大体了解,Spring框架是为了方便我们编程的。尤其是一些特别麻烦的初始化和结束过程。
@Autowired
private SessionFactory sessionFactory;
//获取和当前线程绑定的Session
private Session getSession(){
return sessionFactory.getCurrentSession();
}
@Override public void saveBook(Book book){
getSession().save(book);
}
啥叫麻烦的初始化和结束过程?
例如:之前写的
单独使用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{
}
十个步骤变成了2个步骤:
5、最后获取Session
8、用Session做
增、删、改、查
非常方便。
但当我要实现用Session来删除一行时,却出现了问题。因为Spring终归是管理类的类工厂,你要是没指定它生产你想要的东西,那么它就不会在那里。我们重新看一下beans.xml文件:
<tx:advice id="txAdvice" transaction-manager="transactionManager">
</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
sun.reflect.NativeMethodAccessorImpl
sun.reflect.DelegatingMethodAccessor
org.springframework.aop.support.AopUtils.invokeJoinpointUsingRefl
org.springframework.aop.framework.ReflectiveMethodInvocati
org.springframework.aop.framework.ReflectiveMethodInvocati
org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.
org.springframework.transaction.interceptor.TransactionAspectSupport
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.
org.springframework.aop.framework.ReflectiveMethodInvocati
org.springframework.aop.interceptor.ExposeInvocationIntercep
org.springframework.aop.framework.ReflectiveMethodInvocati
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.
com.sun.proxy.$Proxy194.deleteById(Unknown Source)
myController1.HiFirstApp.addNewWord(HiFirstApp.
sun.reflect.NativeMethodAccessorImpl
sun.reflect.NativeMethodAccessorImpl
sun.reflect.DelegatingMethodAccessor
org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerM
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAda
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAda
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAda
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>
|
我们很容易看出,delete加个*(星号)是一个正则表达式匹配,也就是我们在WordBOImpl.java里面写的代码,无论是deleteById,还是deleteByName,只要是delete开头的,都会给它匹配一个Transaction(事务)。然后当修改失败后,我们也能看到xml定义了rollback-for方法,当出现exception的时候就回滚。
这是典型的AOP(面向切面)编程。
于是以下的代码才能够顺利在SSH里面运行:
|
后记:ObjectNotFoundException的问题
我试验过以下代码:
|
这个问题发生在“MySQL那个表里面没这个id,你却硬要删除以此id开始的那一行”的情况。
但有趣的事情是这个Object Not Found并不是空指针错误,session.load还真真切切把这个Word给load出来了,而且你用getID方法也不会出错,返回的确实是你要查询的那个ID。问题在于除了ID,别的啥都没有。这个Word类已经被改造过了,使用任何除查询ID以外的方法,都会报这个ObjectNotFoundException。看来Spring的工厂类不是盖的,的确将我们的Word改造了。
于是干脆在删除的时候try一下,这样比较好。就像之前的一样,简洁大方:
|