背景
上一章详细的描述了spring如何通过代理方法上的属性生成TrasactionAttribute,继而查找TrasactionManager。详细介绍了TrasactionAttribute的结构,查找TrasactionManager的流程,生成TrasactionAttribute的流程,延伸讲解了TransactionInterceptor和TransactionAspectSupport两个类的关系,spring如何将AOP模块和事务模块结合起来,其核心思想。大家将来在扩展spring AOP时,可以借鉴spring的思想。在抽象类Support处理核心业务,另一个类比如MybuzzInterceptor实现spring AOP接口,同时继承TransactionAspectSupport,这样MybuzzInterceptor就只是AOP和核心业务的桥梁,解耦AOP模块和你的业务模块。
流程
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification)
上一步已经生成了TrasactionManager,TrasactionAttribute,这一步就是如何使用这些数据。比如hibernate增删查改数据库时,会生成session,而这步就是要执行该行为。TransactionInfo,spring管理事务的核心类,先分析该类。transactionManager,transactionAttribute,joinpointIdentification,这三个属性在上步已经生成了;oldTransactionInfo,上个对象的引用,说明这是一个链表结构,有链表说明要循环遍历?为何要这么使用,大家可以思考下!提示:spring管理的service嵌套调用,涉及到spring事务的传播特性。
protected final class TransactionInfo {
private final PlatformTransactionManager transactionManager;
private final TransactionAttribute transactionAttribute;
private final String joinpointIdentification;
private TransactionStatus transactionStatus;
private TransactionInfo oldTransactionInfo;
public TransactionInfo(PlatformTransactionManager transactionManager,
TransactionAttribute transactionAttribute, String joinpointIdentification) {
this.transactionManager = transactionManager;
this.transactionAttribute = transactionAttribute;
this.joinpointIdentification = joinpointIdentification;
}
再看如何生成TransactionInfo。
protected TransactionInfo createTransactionIfNecessary(
if (txAttr != null && txAttr.getName() == null) {
txAttr = new DelegatingTransactionAttribute(txAttr) {
@Override
public String getName() {
return joinpointIdentification;
}
};
}
}
没有定义事务名时,以joinpointIdentification来命名。又一次使用了匿名内部类,其目的是为了生成TransactionAttribute.name,DelegatingTransactionAttribute继承了DelegatingTransactionDefinition的抽象类,实现了TransactionAttribute接口。TransactionDefine接口定义了getName()方法,
生成TrasactionStatus
TrasactionStatus 是spring事务模块的核心接口,我们先看接口定义:
public interface TransactionStatus extends SavepointManager, Flushable {
boolean isNewTransaction();
boolean hasSavepoint();
void setRollbackOnly();
boolean isRollbackOnly();
void flush();
boolean isCompleted();
}
public interface SavepointManager {
Object createSavepoint() throws TransactionException;
void rollbackToSavepoint(Object savepoint) throws TransactionException;
void releaseSavepoint(Object savepoint) throws TransactionException;
}
通过接口方法,也大致能推测与事务的执行状态有关,比如isCompleted可能会影响事务执行完毕后的清理。
获取事务的核心代码如下,这是org.springframework.orm.hibernate5.HibernateTransactionManager生成事务的代码:
protected Object doGetTransaction() {
HibernateTransactionObject txObject = new HibernateTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
if (sessionHolder != null) {
if (logger.isDebugEnabled()) {
logger.debug("Found thread-bound Session [" + sessionHolder.getSession() + "] for Hibernate transaction");
}
txObject.setSessionHolder(sessionHolder);
}
else if (this.hibernateManagedSession) {
try {
Session session = this.sessionFactory.getCurrentSession();
if (logger.isDebugEnabled()) {
logger.debug("Found Hibernate-managed Session [" + session + "] for Spring-managed transaction");
}
txObject.setExistingSession(session);
}
catch (HibernateException ex) {
throw new DataAccessResourceFailureException(
"Could not obtain Hibernate-managed Session for Spring-managed transaction", ex);
}
}
if (getDataSource() != null) {
ConnectionHolder conHolder = (ConnectionHolder)
TransactionSynchronizationManager.getResource(getDataSource());
txObject.setConnectionHolder(conHolder);
}
return txObject;
}
- 生成HibernateTransactionObject,如果该transactionManager支持嵌套式事务,HibernateTransactionObject即支持设置savePoint。
- 生成sessionHolder,根据变量名,推测他可能是真实session(即Hibernate实现的session)的句柄,代码如下:
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory())
spring配置文件中配置transactionManager,注入了sessionFactory,getSessionFactory()
就是获取注入的sessionFactory。大家这时就明白transactionManager和sessionFactory的关系了吧。getResource()
方法是TransactionSynchronizationManager类(抽象类)的静态方法。
TransactionSynchronizationManager类中定义了线程变量ThreadLocal<Map<Object, Object>>=new NamedThreadLocal<Map<Object, Object>>("Transactional resources")
,
private static Object doGetResource(Object actualKey) {
Map<Object, Object> map = resources.get();
if (map == null) {
return null;
}
Object value = map.get(actualKey);
// Transparently remove ResourceHolder that was marked as void...
if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
map.remove(actualKey);
// Remove entire ThreadLocal if empty...
if (map.isEmpty()) {
resources.remove();
}
value = null;
}
return value;
}
以上是getResource核心代码,该方法就是根据actualKey作为key从线程变量中查对应的value。简单来说就是在某一步会将sessionFactory放入到这个线程变量中。在调试过程中,当前值为null,所以返回的sessionHolder也为null
sessionHolder为null,判断当前是否为hibernate管理事务,如果是,则调用sessionFactory.getCurrentSession()。
获取connectionHolder,同事务,不过是以datasource作为key,当前返回的仍然是null。
以上就是doGetTransaction()方法的整个过程,可以分为3步。
- 生成HibernateTransactionObject
- 在线程变量中获取sessionHolder,并设置到HibernateTransactionObject
- 在线程变量中获取connectionHolder,并设置到HibernateTransactionObject
判断该事务是否是正在使用的事务,判断条件
txObject.hasSpringManagedTransaction() ||
(this.hibernateManagedSession && txObject.hasHibernateManagedTransaction())
在spring 管理事务模式下,就是sessionHolder是否为Null, null就是新事务,否则就是当前事务。
如果是当前事务,走handleExistingTransaction(definition, transaction, debugEnabled)
,后续再看。
非当前正在使用的事务:即要创建新事务属性,因为sessionHolder,connectionHolder都是null
判断事务属性的传播特性是否为PROPAGATION_MANDATORY(当前必须存在在事务),如果是,抛出异常,因为当前不存在事务
判断传播特性是否为PROPAGATION_REQUIRED或者PROPAGATION_REQUIRES_NEW或者PROPAGATION_NESTED(他们的共同点是创建新事务)
我配置的是PROPAGATION_REQUIRED,以下该分支下相应代码
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
}
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException ex) {
resume(null, suspendedResources);
throw ex;
}
catch (Error err) {
resume(null, suspendedResources);
throw err;
}
以上代码暂不考虑,暂时不明白
生成DefaultTransactionStatus,这就是本章最终返回的结果,这是最外层的方法
status = tm.getTransaction(txAttr)
Session newSession = (entityInterceptor != null ?
getSessionFactory().withOptions().interceptor(entityInterceptor).openSession() :
getSessionFactory().openSession());
openSession说明了是打开一个新的session,HibernateTransactionObject生成sesssionHolder,holder保存session
如果配置的事务属性是readOnly并且是新事务,则将session.setFlushMode(FlushMode.MANUAL),如果是readOnly,但不是新事务,那么就重新设置flushMode。
当配置事务超时时间为默认-1时,则使用纯粹的hibernate事务,
Transaction hibTx = session.beginTransaction();
保存真正的事务对象到sessionHolder
如果dataSource不为空,通过session获取物理连接connection,保存到connectionHolder,并以dataSource做为key,connectionHolder作为value,保存到之前介绍的线程变量resources中。
同时将sessionHolder作为value,sessionFactory作为key,也保存到resources中
protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
if (status.isNewSynchronization()) {
TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction());
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT ?
definition.getIsolationLevel() : null);
TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
TransactionSynchronizationManager.initSynchronization();
}
}
该方法只有在新生成的事务才会生效,都是配置到线程变量中
以上就是获得TransactioStatus的具体步骤。
- 生成HibernateTransactionObject
- 以sessionFactory为key到线程变量resource中查sessionHolder,以datasource为key到线程变量resource中查connectionHolder,如果没有,表示要生成新的事务,走步骤3
- 调用hibernate的sessionFactory.openSession()创建新的session,保存到sessionHolder,同时生成transaction,将sessionHolder和connectionHolder都保存到resource中
- session中调用beginTransaction()启动事务,同时将transaction保存到sessionHolder中
生成TransactionStatus后,然后在生成TransactionInfo,该对象相当于集中保存了TransactionStatus,transactionAttribute,TransactionPlateformManager,之后存到线程变量transactionInfoHolder中,TransactionInfo是个链表结构,在transactionInfoHolder是链表头指针,bindThread就是首部插入节点。
protected TransactionInfo prepareTransactionInfo(PlatformTransactionManager tm,
TransactionAttribute txAttr, String joinpointIdentification, TransactionStatus status) {
TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
if (txAttr != null) {
// We need a transaction for this method
if (logger.isTraceEnabled()) {
logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
}
// The transaction manager will flag an error if an incompatible tx already exists
txInfo.newTransactionStatus(status);
}
else {
// The TransactionInfo.hasTransaction() method will return
// false. We created it only to preserve the integrity of
// the ThreadLocal stack maintained in this class.
if (logger.isTraceEnabled())
logger.trace("Don't need to create transaction for [" + joinpointIdentification +
"]: This method isn't transactional.");
}
// We always bind the TransactionInfo to the thread, even if we didn't create
// a new transaction here. This guarantees that the TransactionInfo stack
// will be managed correctly even if no transaction was created by this aspect.
txInfo.bindToThread();
return txInfo;
}
总结
本章详细介绍了TransactionStatus如何生成,TransactionInfo如何生成。大家应该了解基本的对象关系,TransactionInfo, TransactionStatus, HibernateTransactionObject, SessionHolder,ConnectionHolder, session, transaction,已经目前使用的线程变量,主要是保存sessionHolder和connectionHolder的resource,还有持有transactionInfo的transactionInfoHolder