Spring事务管理器PlatformTransactionManager

1: jdbc事务例子

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:分析

  • 怎么使用事务

    将自动提交设置为false,即conn.setAutoCommit(false),然后手动来conn.commit()、或者conn.rollback()。

  • 一个重要意识

    conn.commit();conn.rollback()等这些属于事务代码,其他执行sql的代码属于业务代码

    只有事务代码和业务代码使用的是同一个Connection的时候,事务的回滚和提交才能正常执行,所以如果我们要实现事务代码和业务代码的分离,必须要保证他们使用的是同一个Connection。

  • 谁在执行事务

    我们可以看到,可以通过操作Connection连接来执行事务,这并不代表Connection具有事务功能,而是使用了数据库自身的事务功能,Connection仅仅是把一些命令如commit、rollback传递给数据库

3 存在的问题

  • 1 业务代码都要嵌套在try catch事务模板代码中

  • 2 当存在多个类似save(User user)的业务逻辑时,没法保证他们的原子性

login(user);
save(user);

这两个业务逻辑都是相似的代码,获取Connection连接,然后执行sql语句。没法保证它们的原子性,是因为它们使用的不是同一个连接,不在同一个事务内。

4 Hibernate的事务例子

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();
	}
}
  • 事务功能和业务功能的分离

    jdbc事务中Connection负担了两方面的功能,事务功能和执行sql的功能。这里的Transaction是Hibernate自己定义的事务,Hibernate则把这两者的功能单独开来,将事务功能交给了Transaction,使得职责更加分工明确。

  • 事务的原理

    其实Session、Transaction内部会有一个相同的Connection,这样就保证了 业务代码和事务代码使用的是同一个Connection,Transaction事务的回滚都是依托内部的Connection来完成的,如下:

  • 事务的开始,设置自动提交为false

äºå¡çå¼å§

  • 事务的提交,通过connection的commit方法来提交

äºå¡çæ交

 

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

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

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

先来看下三大接口

  • PlatformTransactionManager : 事务管理器

  • TransactionDefinition : 事务的一些基础信息,如超时时间、隔离级别、传播属性等

  • TransactionStatus : 事务的一些状态信息,如是否是一个新的事务、是否已被标记为回滚

看下PlatformTransactionManager如何来操作事务:

public interface PlatformTransactionManager {

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

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

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

7 事务定义接口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;
	//略
}
  • 事务的传播属性为PROPAGATION_REQUIRED,即当前没有事务的时候,创建一个,如果有则使用当前事务
  • 事务的隔离级别采用底层数据库默认的隔离级别
  • 超时时间采用底层数据库默认的超时时间
  • 是否只读为false

8 事务接口定义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的选择可能如下:

  • DataSourceTransactionObject
  • HibernateTransactionObject
  • JpaTransactionObject(之后再详细说)

详细信息分别如下:

  • 对于DataSourceTransactionObject:

    我们使用了dataSource来获取连接,要想实现事务功能,必然需要使用Connection,所以它中肯定有一个Connection来执行事务的操作。

    DataSourceTransactionObject中有一个ConnectionHolder,它封装了一个Connection。

  • 对于HibernateTransactionObject:

    我们使用了hibenrate,此时要想实现事务功能,必然需要通过hibernate自己定义的Transaction来实现。

    HibernateTransactionObject中含有一个SessionHolder,和上面的ConnectionHolder一样,它封装了一个Session,有了Session,我们就可以通过Session来产生一个Hibernate的Transaction,从而实现事务操作。

9 事务管理器接口定义PlatformTransactionManager

类图关系如下:

é»è®¤çäºå¡å®ä¹

重点来说下

  • AbstractPlatformTransactionManager
    • DataSourceTransactionManager
    • HibernateTransactionManager
    • JpaTransactionManager(之后详细再说)

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

  • 1 第一个接口:TransactionStatus getTransaction(TransactionDefinition definition) 根据事务定义获取事务状态

    大体内容就是先获取上述说明的Object transaction,判断当前事务是否已存在,如果存在则进行事务的传播属性处理,后面详细说明,如果不存在new DefaultTransactionStatus,新创建一个事务,同时使用Object transaction开启事务。 分成了几个过程:

    不同的事务管理器获取不同的Object transaction

    • 1.1 获取Object transaction:
    • DataSourceTransactionManager就是获取上述的DataSourceTransactionObject

      从当前线程中获取绑定的ConnectionHolder,可能为null,如果为null,则会在下一个开启事务的过程中,从dataSource中获取一个Connection,封装成ConnectionHolder,然后再绑定到当前线程

      然后我们new 一个DataSourceTransactionObject了,具体过程如下:

DataSourceTransactionManagerè·åä¸ä¸ªäºå¡

  • HibernateTransactionManager获取HibernateTransactionObject

    从当前线程中获取绑定的SessionHolder,可能为null,如果为null,则会在下一个开启事务的过程中从sessionFactory中获取一个session,然后封装成SessionHolder,然后再绑定到当前线程

    然后我们就可以new 一个HibernateTransactionObject了,具体过程如下:

HibernateTransactionManagerè·åä¸ä¸ªäºå¡

10 构建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());
		}

11 第二个接口:void rollback(TransactionStatus status) 回滚事务

  • 回滚,则还是利用DefaultTransactionStatus内部的Object transaction来执行回滚操作

    • DataSourceTransactionManager就是使用DataSourceTransactionObject中的Connection来进行回滚操作

      protected void doRollback(DefaultTransactionStatus status) {
      	DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
      	Connection con = txObject.getConnectionHolder().getConnection();
      	try {
      		con.rollback();
      	}
      	catch (SQLException ex) {
      		throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
      	}
      }
      
    • HibernateTransactionManager就是使用HibernateTransactionObject中的SessionHolder中的Session创建的事务Transaction来进行回滚操作

      protected void doRollback(DefaultTransactionStatus status) {
      	HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
      	try {
      		txObject.getSessionHolder().getTransaction().rollback();
      	}
      }
      
  • 3 第三个接口: void commit(TransactionStatus status) 提交事务

    同理,DataSourceTransactionManager依托内部的Connection来完成提交操作

    HibernateTransactionManager依托内部的Transaction来完成提交操作

  • 12
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值