【Java EE 学习 54】【OA项目第一天】【SSH事务管理不能回滚问题解决】【struts2流程回顾】

1、SSH整合以后事务问题和总结java

  1.引入问题:DAO层测试git

    假设将User对象设置为懒加载模式,在dao层使用load方法。github

     

    注意,注释不要放开。web

    使用以下的代码块进行测试:spring

    会报错:no session。sql

    

    为何会没有session呢,由于在代码apache

User user=(User) hibernateTemplate.load(User.class, id);

    执行完成以后session就已经关闭了。缓存

  2.Service层测试安全

    (1)Service层代码:服务器

    

      DAO层代码:

     

      测试代码:

    

    运行结果:

    

    出现的错误结果和上面彻底相同。

    (2)解决错误

      将DAO层中的代码注释去掉或者将Service中的代码注释去掉。

      注释的代码做用是打印结果,只是一个System.out.println方法的执行;虽然如此,程序运行再也不有问题。

      

  3.缘由分析

    (1)为何测试DAO不管怎么测试都会报出异常?

       由于DAO层调用完成getUserById方法以后session就立刻关闭了,因此执行下一句代码的时候即便是打印输出的代码也会报错。

    (2)为何测试Service的时候若是没有去掉注释的话,就会出错?

       由于去掉注释的话,Service层调用完成getUserById方法以后Session就会关闭,效果和在DAO层是彻底相同的,因此结果和在DAO层是彻底相同的。报错的信息彻底相同。

    (3)为何Service层去掉注释以后就不报错了?

      Service层去掉注释以后因为方法尚未退出,因此会将数据保存到User对象中;因此数据已经保存到了内存中,这样就不会报错了。

    (4)在DAO层去掉注释以后会不会报错?

      去掉DAO层的注释以后的运行结果:

      

      结果是没有报错,为何,DAO层调用完成查询的方法以后不是会当即关闭session吗?

        结果是没有关闭Session,缘由是在Service层调用的方法,该方法具备事务,并且该事务的范围扩展到了DAO层。最根本的缘由是在Spring配置文件中的配置:

      

      propagation属性值是默认的,因此在Service层中方法执行的时候,执行的全部方法都将会带有事务,直到方法结束,事务也会随之结束,所以DAO层才没有当即结束事务(关闭session)。

  4.总结SSH整合以后事务管理的范围

    (1)若是当前执行的方法没有事务环境,当执行完成this.hibernateTemplate中的方法以后session当即关闭。

    (2)若是当前执行的方法有事务环境,当事务环境的方法被调用完成以后session关闭。

  5.经过以上的分析和总结能够获得若是直接在Action中调用Service层中的方法,若是出现异常,确定不能回滚,例以下面中的测试代码:   

     

    很明显,这里有/0的异常,因此若是事务可以回滚,则不会发出insert的sql语句。可是结果倒是:

     

    因此事务回滚失败了。缘由就是Service对象中的每个方法执行完成以后都会当即关闭session,事务也随之消失。相同Service中的方法调用屡次或者相同Service中的不一样方法执行的时候必定不会在同一个事务中。

2、解决SSH整合以后的事务问题

  解决方法就是使用OSIV模式(Open Session In View),即在MVC中的View层就开启事务,这样就扩展了事务的范围。

  只是在web.xml文件中加上以下的配置便可:

    <!-- 使用OSIV模式解决事务回滚问题,只须要添加一个监听器就能够了 -->
    <filter>
        <filter-name>OpenSessionInViewFilter</filter-name>
        <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>OpenSessionInViewFilter</filter-name>
        <url-pattern>*.action</url-pattern>
    </filter-mapping>

  也就是说只是增长了一个过滤器而已,应当注意该过滤器放置的位置应当在下面的配置上面:

<filter>
        <filter-name>strutsFilter</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>strutsFilter</filter-name>    
        <url-pattern>*.action</url-pattern>
    </filter-mapping>

  不然添加的过滤器不生效。完整的web.xml文件配置以下:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <web-app version="3.0" 
 3     xmlns="http://java.sun.com/xml/ns/javaee" 
 4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 5     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
 6     http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
 7     
 8     
 9         <!-- 使用OSIV模式解决事务回滚问题,只须要添加一个监听器就能够了 -->
10     <filter>
11         <filter-name>OpenSessionInViewFilter</filter-name>
12         <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
13     </filter>
14     <filter-mapping>
15         <filter-name>OpenSessionInViewFilter</filter-name>
16         <url-pattern>*.action</url-pattern>
17     </filter-mapping>
18     
19     <filter>
20         <filter-name>strutsFilter</filter-name>
21         <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
22     </filter>
23     <filter-mapping>
24         <filter-name>strutsFilter</filter-name>    
25         <url-pattern>*.action</url-pattern>
26     </filter-mapping>
27     
28 
29     
30     <listener>
31         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
32     </listener>
33     <context-param>
34         <param-name>contextConfigLocation</param-name>
35         <param-value>classpath:spring/applicationContext.xml</param-value>
36     </context-param>
37     
38   <welcome-file-list>
39     <welcome-file>index.jsp</welcome-file>
40   </welcome-file-list>
41 </web-app>
web.xml

  最后,使用OSIV模式应当注意的事项:

    1.使用OSIV模式以后,sessio的打开被提早了,session的关闭被延后了,这样就解决了懒加载引发的异常的问题。

    2.两个过滤器,OSIV的过滤器必须在struts2以前。

  使用OSIV模式的缺点:

    由于Session的关闭被延迟了,因此hibernate的一级缓存在session中,因此会致使大量的缓存数据长期保存在了内存中。

3、Struts2流程回顾

  1.启动服务器的时候干了两件事情。

    

      * dispatcher = init.initDispatcher(config);该句代码加载了各类各样的配置文件。

      * init.initStaticContentLoader(config, dispatcher); 该句代码完成了静态注入。

  2.当过滤器拦截到一个请求的时候作了什么事情

    查看doFilter方法中的源代码。

    (1)建立AciontContext对象。

      建立ActionContext对象的同时会同时建立ValueStack对象,并且建立ValueStack对象在前,建立ActionContext对象在后。

    两个对象同时建立,并且两个对象维护同一个Map对象,缘由是建立ActionContext的时候使用的参数是ValueStack对象的context成员变量。

   经过代码ActionContext.setContext(tx);便可以将ActionContext放置到ThreadLocal中了,这样数据就安全了,下面是代码追踪。

    (2)建立ActionProxy对象

    init方法中执行了建立了对应的Action和全部的拦截器。

    

    最后在invocation的invoke方法中执行全部的拦截器、执行当前请求的action、执行结果集。

    

4、Struts2的完整流程图

  

 

最后附上项目源代码:https://github.com/kdyzm/day53_ssh_oa

相关文章
相关标签/搜索