由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级别的。

thread

2.调用sessionFactory的getCurrentSession方法:

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:

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的实现,而不用担心某个地方的事务是否关闭。

this.getHibernateTemplate().save(user);


关于异常与事务回滚:   

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

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

不会回滚:  

public void addUser(User user)

   throws Exception {

      this.getHibernateTemplate().save(user);

         //若干操作……          

      throw new Exception();

   }
 

回滚:

  public void addUser(User user) {

         this.getHibernateTemplate().save(user);    

         //若干操作……       

         throw new RuntimeException();

   }


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

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

 



   

   

      

         classpath:hibernate.cfg.xml

      

   
  

   

   

      

                 

      

   
  

   

   

      

      

   
  

    

   

      

         

         

         

         

      

   

 

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

    update

applicationContext-beans.xml:

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

 



          

   

      

      

   
  

   

      

   


事务传播特性:

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

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

由openSession、getCurrentSession和HibernateDaoSupport浅谈Spring对事物的支持_第1张图片

 

Spring事务的隔离级别:

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

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

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

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

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

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

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

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

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

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

你可能感兴趣的:(Java)