分布式事务系列(1.1)Spring事务管理器PlatformTransactionManager

时间:2015-05-15 07:54:42   收藏:0   阅读:267

1 系列目录

2 jdbc事务

2.1 例子

public void save(User user) throws SQLException{
    Connection conn=jdbcDao.getConnection();
    conn.setAutoCommit(false);
    try {
       PreparedStatement ps=conn.prepareStatement("insert into user(name,age) value(?,?)");
       ps.setString(1,user.getName());
       ps.setInt(2,user.getAge());
       ps.execute();
       conn.commit();
    } catch (Exception e) {
       e.printStackTrace();
       conn.rollback();
    }finally{
       conn.close();
    }
}

2.2 分析

2.3 存在的问题

3 Hibernate的事务

3.1 例子

public void save(User user){
    Session session=hibernateDao.openSession();
    Transaction tx=null;
    try {
       tx=session.beginTransaction();  
        session.save(user);  
        tx.commit();  
    } catch (Exception e) {
       if(tx!=null){
         tx.rollback();
       }
    }finally{
       session.close();
    }
}

3.2 分析

4 Spring事务功能的总体接口设计

由于上述各家实现事务功能的方式各不相同,Spring进行了统一的抽象,形成了PlatformTransactionManager事务管理器接口,事务的提交、回滚等操作全部交给它来实现。Spring的事务体系也是在PlatformTransactionManager事务管理器接口上开展开来的,所以先来了解下PlatformTransactionManager事务管理器。

4.1 事务功能的总体接口设计

先来看下三大接口

看下PlatformTransactionManager如何来操作事务:

public interface PlatformTransactionManager {

    //根据事务定义TransactionDefinition,获取事务
    TransactionStatus getTransaction(TransactionDefinition definition);

    //提交事务
    void commit(TransactionStatus status);

    //回滚事务
    void rollback(TransactionStatus status);
}

4.2 接口对应的实现

4.2.1 事务定义接口TransactionDefinition

技术分享

要明白的地方:

事务的隔离级别是数据库本身的事务功能,然而事务的传播属性则是Spring自己为我们提供的功能,数据库事务没有事务的传播属性这一说法。

该接口的实现DefaultTransactionDefinition:默认的事务定义

public class DefaultTransactionDefinition implements TransactionDefinition, Serializable {
    private int propagationBehavior = PROPAGATION_REQUIRED;
    private int isolationLevel = ISOLATION_DEFAULT;
    private int timeout = TIMEOUT_DEFAULT;
    private boolean readOnly = false;
    //略
}

4.2.2 事务接口定义TransactionStatus

先引出Connection连接中的保存点功能:

//创建一个保存点
conn.setSavepoint(name);
//回滚到某个保存点
conn.rollback(savepoint);
//释放某个保存点
conn.releaseSavepoint(savepoint);

TransactionStatus它继承了SavepointManager接口,SavepointManager是对事务中上述保存点功能的封装,如下:

public interface SavepointManager {
    Object createSavepoint() throws TransactionException;
    void rollbackToSavepoint(Object savepoint) throws TransactionException;
    void releaseSavepoint(Object savepoint) throws TransactionException;
}

Spring利用保存点功能实现了事务的嵌套功能。后面会详细说明。

TransactionStatus本身更多存储的是事务的一些状态信息:

技术分享

常用的TransactionStatus接口实现为DefaultTransactionStatus:

技术分享

目前jdbc事务是通过Connection来实现事务的,Hibernate是通过它自己定义的Transaction来实现的,所以各家的事务都不同,所以Spring只能以Object transaction的形式来表示各家的事务,事务的回滚和提交等操作都会最终委托给上述Object transaction来完成。

Object transaction的职责就是提交回滚事务,这个transaction的选择可能如下:

详细信息分别如下:

4.2.3 事务管理器接口定义PlatformTransactionManager

类图关系如下:

技术分享

重点来说下

这就需要来看看事务管理器的接口,上述的他们都是怎么实现的:

-   1.2 构建DefaultTransactionStatus,使用Object transaction开启事务

    -  DataSourceTransactionManager的DataSourceTransactionObject开启过程如下:

       首先判断之前的获取当前线程绑定的ConnectionHolder是否为null,如果为null,从dataSource中获取一个Connection,封装成ConnectionHolder,然后再绑定到当前线程

       因为开启了一个事务,则必须要关闭DataSourceTransactionObject中Connection的自动提交,代码如下(省略一些):

         protected void doBegin(Object transaction, TransactionDefinition definition) {
          DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
          Connection con = null;

          //如果ConnectionHolder是否为null,从新获取
          if (txObject.getConnectionHolder() == null ||
                 txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
              Connection newCon = this.dataSource.getConnection();
              txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
          }
          con = txObject.getConnectionHolder().getConnection();

          Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
          txObject.setPreviousIsolationLevel(previousIsolationLevel);

          //取消自动提交
          if (con.getAutoCommit()) {
              txObject.setMustRestoreAutoCommit(true);
              if (logger.isDebugEnabled()) {
                 logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
              }
              con.setAutoCommit(false);
          }
          txObject.getConnectionHolder().setTransactionActive(true);


          //如果是新增的ConnectionHolder,则绑定到当前线程
          if (txObject.isNewConnectionHolder()) {
              TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
          }
         }



    -  HibernateTransactionManager的HibernateTransactionObject开启过程如下:

       也是同样的逻辑,如果SessionHolder为null,则从SessionFactory中获取一个Session,然后封装成SessionHolder,然后把这个SessionHolder绑定到当前线程

         Session newSession = (entityInterceptor != null ?
              getSessionFactory().withOptions().interceptor(entityInterceptor).openSession() :
              getSessionFactory().openSession());
         txObject.setSession(newSession);

       同时,使用上述session开启一个事务,把事务对象也保存到上述的SessionHolder中。

         Transaction hibTx=session.beginTransaction();
         txObject.getSessionHolder().setTransaction(hibTx);

       如果是新创建的SessionHolder,则绑定到当前线程

         // Bind the session holder to the thread.
         if (txObject.isNewSessionHolder()) {
          TransactionSynchronizationManager.bindResource(getSessionFactory(), txObject.getSessionHolder());
         }

4.3 事务的传播属性解析

可以参考这篇文章的案例说明Spring事务的传播行为和隔离级别,下面重点源码分析下Spring的事务传播属性:

对于事务的传播属性的代码如下:

技术分享

在获取Object transaction之后,先进行判断,是否是已存在的事务。因为这个Object transaction的获取过程就是直接从线程绑定的获取的,可能当前线程已经存在事务,具体判断如下:

如果是已存在事务:则需要对事务的传播属性进行处理,如下即上述截图中的的handleExistingTransaction方法:

至此事务管理器接口就简略说完了,还有很多细节的东西,需要各位再去仔细研究。

5 结束语

了解了PlatformTransactionManager事务管理器,下面就要开展Spring的编程式事务、声明式事务,所以下一篇文章内容如下:

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!