• 由openSession、getCurrentSession和HibernateDaoSupport浅谈Spring对事物的支持


    由openSession、getCurrentSession和HibernateDaoSupport浅谈Spring对事物的支持

        Spring和Hibernate的集成的一个要点就是对事务的支持,openSession、getCurrentSession都是编程式事务(手动设置事务的提交、回滚)中重要的对象,HibernateDaoSupport则提供了更方便的声明式事务支持。

        Hibernate中最重要的就是Session对象的引入,它是对jdbc的深度封装,包括对事务的处理,Session对象通过SessionFactory来管理,openSession和getCurrentSession是管理session的重要的方法。

        openSession和getCurrentSession的根本区别在于有没有绑定当前线程,所以,使用方法有差异:

    * openSession没有绑定当前线程,所以,使用完后必须关闭,

    * currentSession和当前线程绑定,在事务结束后会自动关闭。

    关于事务的边界和传播:

         通常情况下事务的边界需要设置在业务逻辑处理层中,但是,如果在一个业务中涉及到多个业务逻辑层之间的方法,且需要在同一个事务中运行,那么,这就涉及到了事务的传播性。

    如果使用openSession,就要在dao层的方法中传递session,而这种做法是很糟糕的,首先增加了参数的个数,另外,方法是否需要事务,完全是可以当做一种独立的服务抽离出的。

    因为currentSession是线程级别的,所以,只要业务逻辑方法在同一个线程中,就不会担心上面的问题。这也是currentSession的一个优越处之一。

    使用currentSession:

    1.在配置文件中将线程配置成Thread级别的。

    1. <SPAN style="FONT-SIZE: 18px"><propertynamepropertyname="hibernate.current_session_context_class">thread</property></SPAN>  
    <propertyname="hibernate.current_session_context_class">thread</property>

    2.调用sessionFactory的getCurrentSession方法:

    1. <SPAN style="FONT-SIZE: 18px">publicvoid addUser(User user) {  
    2.   
    3.     Session session = null;  
    4.   
    5.     try {  
    6.   
    7.        session =HibernateUtils.getSessionFactory().getCurrentSession();  
    8.   
    9.        session.beginTransaction();        
    10.   
    11.        session.save(user);          
    12.   
    13.        Loglog = new Log();  
    14.   
    15.        log.setType("操作日志");  
    16.   
    17.        log.setTime(new Date());  
    18.   
    19.        log.setDetail("XXX");        
    20.   
    21.        LogManager logManager = newLogManagerImpl();  
    22.   
    23.        logManager.addLog(log);         
    24.   
    25.        session.getTransaction().commit();  
    26.   
    27.     }catch(Exception e) {  
    28.   
    29.        e.printStackTrace();  
    30.   
    31.        session.getTransaction().rollback();     
    32.   
    33.     }  
    34.   
    35. }</SPAN>  
    publicvoid addUser(User user) {
    
        Session session = null;
    
        try {
    
           session =HibernateUtils.getSessionFactory().getCurrentSession();
    
           session.beginTransaction();      
    
           session.save(user);        
    
           Loglog = new Log();
    
           log.setType("操作日志");
    
           log.setTime(new Date());
    
           log.setDetail("XXX");      
    
           LogManager logManager = newLogManagerImpl();
    
           logManager.addLog(log);       
    
           session.getTransaction().commit();
    
        }catch(Exception e) {
    
           e.printStackTrace();
    
           session.getTransaction().rollback();   
    
        }
    
    }

    使用openSession:

    1. <SPAN style="FONT-SIZE: 18px">public void addUser(User user) {  
    2.   
    3.       Sessionsession = null;  
    4.   
    5.       try{  
    6.   
    7.          session= HibernateUtils.getSession();  
    8.   
    9.          session.beginTransaction();  
    10.   
    11. // 若干操作…………           
    12.   
    13.          session.getTransaction().commit();  
    14.   
    15.       }catch(Exceptione) {  
    16.   
    17.          e.printStackTrace();  
    18.   
    19.          session.getTransaction().rollback();  
    20.   
    21.       }finally{  
    22.   
    23.          HibernateUtils.closeSession(session);  
    24.   
    25.       }  
    26.   
    27.    }  
    28.   
    29.  </SPAN>  
    public void addUser(User user) {
    
          Sessionsession = null;
    
          try{
    
             session= HibernateUtils.getSession();
    
             session.beginTransaction();
    
    // 若干操作…………        
    
             session.getTransaction().commit();
    
          }catch(Exceptione) {
    
             e.printStackTrace();
    
             session.getTransaction().rollback();
    
          }finally{
    
             HibernateUtils.closeSession(session);
    
          }
    
       }
    
     

    使用HibernateDaoSupport声明式事务:

        Spring与Hibernate的集成使用最多的是HibernateDaoSupport,它对session的获取以及事务做了进一步的封装,只需要关注dao的实现,而不用担心某个地方的事务是否关闭。

    1. <SPAN style="FONT-SIZE: 18px">this.getHibernateTemplate().save(user);</SPAN>  
    this.getHibernateTemplate().save(user);

     

    关于异常与事务回滚:   

        Spring在遇到运行期异常(继承了RuntimeException)的时候才会回滚,如果是Exception(如用户输入密码错误)抛出就好,事务会继续往下进行。

        Spring对异常的处理的灵活性还是比较高的,可以配置遇到某个Exception进行回滚,某个RuntimeException不回滚,但是对于EJB就没有这么灵活了,EJB相当于是固定的套餐。

    不会回滚:  

    1. public void addUser(User user)  
    2.   
    3.    throws Exception {  
    4.   
    5.       this.getHibernateTemplate().save(user);  
    6.   
    7.          //若干操作……             
    8.   
    9.       throw new Exception();  
    10.   
    11.    }  
    public void addUser(User user)
    
       throws Exception {
    
          this.getHibernateTemplate().save(user);
    
             //若干操作……          
    
          throw new Exception();
    
       }
     

    回滚:

    1. public void addUser(User user) {  
    2.   
    3.        this.getHibernateTemplate().save(user);      
    4.   
    5.        //若干操作……          
    6.   
    7.        throw new RuntimeException();  
    8.   
    9.  }  
      public void addUser(User user) {
    
             this.getHibernateTemplate().save(user);    
    
             //若干操作……       
    
             throw new RuntimeException();
    
       }

     

    Spring与Hibernate的集成,使用HibernateDaoSupport的配置:

       在ssh框架应用中,Spring与Hibernate的事务集成基本上是比较固定的,我们把事务的集成单独配置到applicationContext-common.xml中:

    1. <SPAN style="FONT-SIZE: 18px"><?xml version="1.0"encoding="UTF-8"?>   
    2.   
    3. <beansxmlnsbeansxmlns="http://www.springframework.org/schema/beans"  
    4.   
    5.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    6.   
    7.        xmlns:aop="http://www.springframework.org/schema/aop"  
    8.   
    9.        xmlns:tx="http://www.springframework.org/schema/tx"  
    10.   
    11.         xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.0.xsd  
    12.   
    13.           http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-2.0.xsd  
    14.   
    15.            http://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-2.0.xsd">  
    16.   
    17.    <!--配置SessionFactory -->  
    18.   
    19.    <beanidbeanid="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">  
    20.   
    21.       <propertynamepropertyname="configLocation">  
    22.   
    23.          <value>classpath:hibernate.cfg.xml</value>  
    24.   
    25.       </property>  
    26.   
    27.    </bean>  
    28.     
    29.   
    30.    <!--配置事务管理器 -->  
    31.   
    32.    <beanidbeanid="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager">  
    33.   
    34.       <propertynamepropertyname="sessionFactory">  
    35.   
    36.          <refbeanrefbean="sessionFactory"/>          
    37.   
    38.       </property>  
    39.   
    40.    </bean>  
    41.     
    42.   
    43.    <!--那些类那些方法使用事务 -->  
    44.   
    45.    <aop:config>  
    46.   
    47.       <aop:pointcutidaop:pointcutid="allManagerMethod" expression="execution(*com.bjpowernode.usermgr.manager.*.*(..))"/>  
    48.   
    49.       <aop:advisorpointcut-refaop:advisorpointcut-ref="allManagerMethod" advice-ref="txAdvice"/>  
    50.   
    51.    </aop:config>  
    52.     
    53.   
    54.    <!--事务的传播特性 -->   
    55.   
    56.    <tx:adviceidtx:adviceid="txAdvice" transaction-manager="transactionManager">  
    57.   
    58.       <tx:attributes>  
    59.   
    60.          <tx:methodnametx:methodname="add*" propagation="REQUIRED"/>  
    61.   
    62.          <tx:methodnametx:methodname="del*" propagation="REQUIRED"/>  
    63.   
    64.          <tx:methodnametx:methodname="modify*" propagation="REQUIRED"/>  
    65.   
    66.          <tx:methodnametx:methodname="*" propagation="REQUIRED"read-only="true"/>  
    67.   
    68.       </tx:attributes>  
    69.   
    70.    </tx:advice>  
    71.   
    72. </beans></SPAN>  
    <?xml version="1.0"encoding="UTF-8"?> 
    
    <beansxmlns="http://www.springframework.org/schema/beans"
    
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    
           xmlns:aop="http://www.springframework.org/schema/aop"
    
           xmlns:tx="http://www.springframework.org/schema/tx"
    
            xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.0.xsd
    
              http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-2.0.xsd
    
               http://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
    
       <!--配置SessionFactory -->
    
       <beanid="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    
          <propertyname="configLocation">
    
             <value>classpath:hibernate.cfg.xml</value>
    
          </property>
    
       </bean>
      
    
       <!--配置事务管理器 -->
    
       <beanid="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    
          <propertyname="sessionFactory">
    
             <refbean="sessionFactory"/>        
    
          </property>
    
       </bean>
      
    
       <!--那些类那些方法使用事务 -->
    
       <aop:config>
    
          <aop:pointcutid="allManagerMethod" expression="execution(*com.bjpowernode.usermgr.manager.*.*(..))"/>
    
          <aop:advisorpointcut-ref="allManagerMethod" advice-ref="txAdvice"/>
    
       </aop:config>
      
    
       <!--事务的传播特性 --> 
    
       <tx:adviceid="txAdvice" transaction-manager="transactionManager">
    
          <tx:attributes>
    
             <tx:methodname="add*" propagation="REQUIRED"/>
    
             <tx:methodname="del*" propagation="REQUIRED"/>
    
             <tx:methodname="modify*" propagation="REQUIRED"/>
    
             <tx:methodname="*" propagation="REQUIRED"read-only="true"/>
    
          </tx:attributes>
    
       </tx:advice>
    
    </beans>
     

    因为在hibernate.cfg.xml中添加了如下配置,所以,在tomcat等容器启动的时候,会自动将相应的bean对象创建。

    1. <SPAN style="FONT-SIZE: 18px"<propertynamepropertyname="hibernate.hbm2ddl.auto">update</property></SPAN>  
        <propertyname="hibernate.hbm2ddl.auto">update</property>

    applicationContext-beans.xml:

        通常将业务逻辑对实现类的引用单独的xml文件中,同时,在实现类中不能忽略sessionFactory工厂的注入。

    1. <SPAN style="FONT-SIZE: 18px"><?xml version="1.0"encoding="UTF-8"?>   
    2.   
    3. <beansxmlnsbeansxmlns="http://www.springframework.org/schema/beans"  
    4.   
    5.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    6.   
    7.         xmlns:aop="http://www.springframework.org/schema/aop"  
    8.   
    9.        xmlns:tx="http://www.springframework.org/schema/tx"  
    10.   
    11.        xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.0.xsd  
    12.   
    13.            http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-2.0.xsd  
    14.   
    15.           http://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-2.0.xsd">  
    16.   
    17.             
    18.   
    19.    <beanidbeanid="userManager" class="com.bjpowernode.usermgr.manager.UserManagerImpl">  
    20.   
    21.       <propertynamepropertyname="sessionFactory" ref="sessionFactory"/>  
    22.   
    23.       <propertynamepropertyname="logManager" ref="logManager"/>  
    24.   
    25.    </bean>  
    26.     
    27.   
    28.    <beanidbeanid="logManager"class="com.bjpowernode.usermgr.manager.LogManagerImpl">  
    29.   
    30.       <propertynamepropertyname="sessionFactory" ref="sessionFactory"/>  
    31.   
    32.    </bean>  
    33.   
    34. </beans></SPAN>  
    <?xml version="1.0"encoding="UTF-8"?> 
    
    <beansxmlns="http://www.springframework.org/schema/beans"
    
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    
            xmlns:aop="http://www.springframework.org/schema/aop"
    
           xmlns:tx="http://www.springframework.org/schema/tx"
    
           xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.0.xsd
    
               http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-2.0.xsd
    
              http://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
    
              
    
       <beanid="userManager" class="com.bjpowernode.usermgr.manager.UserManagerImpl">
    
          <propertyname="sessionFactory" ref="sessionFactory"/>
    
          <propertyname="logManager" ref="logManager"/>
    
       </bean>
      
    
       <beanid="logManager"class="com.bjpowernode.usermgr.manager.LogManagerImpl">
    
          <propertyname="sessionFactory" ref="sessionFactory"/>
    
       </bean>
    
    </beans>

    事务传播特性:

       为了保证调用的业务逻辑方法都使用同一个事务,通常都使用REQUIRED这个级别,它表示:如果上一个方法中有事务,就直接使用,如果没有,就创建一个事务,这样,一旦事务创建了后,后续调用的方法就不会再创建。

       其他的事务传播特性见下表:


     

    Spring事务的隔离级别:

       1. ISOLATION_DEFAULT: 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。

            另外四个与JDBC的隔离级别相对应。

       2. ISOLATION_READ_UNCOMMITTED: 这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。

            这种隔离级别会产生脏读,不可重复读和幻像读。

       3. ISOLATION_READ_COMMITTED: 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据

       4. ISOLATION_REPEATABLE_READ: 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。

            它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。

       5. ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。

         除了防止脏读,不可重复读外,还避免了幻像读。

        事务隔离级别主要应用在对大数据的处理方面,与锁的机制是密不可分的,这里不赘述。

  • 相关阅读:
    逼哥
    作业
    malloc的底层实现
    docker基本使用
    对mudo中noncopyable类的理解
    整理
    替换war包中的文件
    SpringMVC(1):SpringMVC入门
    MySQL(5):安装MySQL
    MySQL(4):卸载MySQL
  • 原文地址:https://www.cnblogs.com/gtaxmjld/p/4819725.html
Copyright © 2020-2023  润新知