Spring 源代码阅读之声明式事务
事务控制流程
例如对如下代码进行事务控制
class service1{
method1(){
method2();
}
}
class service2{
method2();
}
原理:建立一个method interceptor 拦截service的方法,在方法开始前begin事务,方法结束后commit事务
对于上述例子的流程为:
1)method1 begin transaction,新建一个事务并将该事务存储到当前线程当中,建立一个对象transInfo,存储方法id和transaction引用,并标记status为new
2)method1 proceed(出现异常回滚事务)
3)method2 begin transaction,判断当前线程是否有事务,如果有则使用当前事务,建立一个对象transInfo,标记status为exist
4)method2 proceed(出现异常回滚事务)
5)method2 commit 判断transInfo 状态是否为new,否则跳过提交
6)method1 commit 因为状态是new,所以提交
1. 初始化事务配置信息TransactionProxyFactoryBean
package org.springframework.transaction.interceptor; import java.util.Properties; import org.springframework.aop.Pointcut;
import org.springframework.aop.framework.AbstractSingletonProxyFactoryBean;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.transaction.PlatformTransactionManager; public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBean
implements BeanFactoryAware { private final TransactionInterceptor transactionInterceptor = new TransactionInterceptor(); private Pointcut pointcut; public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionInterceptor.setTransactionManager(transactionManager);
} public void setTransactionAttributes(Properties transactionAttributes) {
this.transactionInterceptor.setTransactionAttributes(transactionAttributes);
} public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
this.transactionInterceptor.setTransactionAttributeSource(transactionAttributeSource);
} public void setPointcut(Pointcut pointcut) {
this.pointcut = pointcut;
} public void setBeanFactory(BeanFactory beanFactory) {
this.transactionInterceptor.setBeanFactory(beanFactory);
} @Override
protected Object createMainInterceptor() {
this.transactionInterceptor.afterPropertiesSet();
if (this.pointcut != null) {
return new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor);
}
else {
// Rely on default pointcut.
return new TransactionAttributeSourceAdvisor(this.transactionInterceptor);
}
} }
2.TransactionInterceptor 事务拦截器
package org.springframework.transaction.interceptor; import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Properties;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.CallbackPreferringPlatformTransactionManager;
import org.springframework.transaction.support.TransactionCallback; @SuppressWarnings("serial")
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
//拦截methods进行事务处理,每个advisor都会进行一次拦截
public Object invoke(final MethodInvocation invocation) throws Throwable {
// Work out the target class: may be <code>null</code>.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null); // If the transaction attribute is null, the method is non-transactional.
final TransactionAttribute txAttr =
getTransactionAttributeSource().getTransactionAttribute(invocation.getMethod(), targetClass);
//获取TransactionManager,一般情况下为配置文件配置好的TranstionManager
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(invocation.getMethod(), targetClass); if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
//开始一个事务,将事务信息封装到TransactionInfo 并绑定到当前线程
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
retVal = invocation.proceed();
}
catch (Throwable ex) {
// target invocation exception
//出现异常时对事务做相应处理
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
//提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
} else {
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
try {
Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
new TransactionCallback<Object>() {
public Object doInTransaction(TransactionStatus status) {
TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
try {
return invocation.proceed();
}
catch (Throwable ex) {
if (txAttr.rollbackOn(ex)) {
// A RuntimeException: will lead to a rollback.
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}
else {
throw new ThrowableHolderException(ex);
}
}
else {
// A normal return value: will lead to a commit.
return new ThrowableHolder(ex);
}
}
finally {
cleanupTransactionInfo(txInfo);
}
}
}); // Check result: It might indicate a Throwable to rethrow.
if (result instanceof ThrowableHolder) {
throw ((ThrowableHolder) result).getThrowable();
}
else {
return result;
}
}
catch (ThrowableHolderException ex) {
throw ex.getCause();
}
}
} }
2.1事务开启相关源代码研究
TransactionInterceptor invoke方法中
//开始一个事务,并将事务信息封装到TransactionInfo
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
跟进该方法源代码:
Class TransactionAspectSupport
protected TransactionInfo createTransactionIfNecessary(
PlatformTransactionManager tm, TransactionAttribute txAttr, final String joinpointIdentification) { // If no name specified, apply method identification as transaction name.
if (txAttr != null && txAttr.getName() == null) {
txAttr = new DelegatingTransactionAttribute(txAttr) {
@Override
public String getName() {
return joinpointIdentification;
}
};
} TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
//如果当前线程中没有事务,则开启一个事务,若事务已经存在,则使用该事务
status = tm.getTransaction(txAttr);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
"] because no transaction manager has been configured");
}
}
}
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
createTransactionIfNecessary方法中
//如果当前线程中没有事务,则开启一个事务,若事务已经存在,则使用该事务
status = tm.getTransaction(txAttr);
跟进该方法源代码:
ClassAbstractPlatformTransactionManager
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
Object transaction = doGetTransaction();//调用具体的TransactionManager实现类获取Transaction // Cache debug flag to avoid repeated checks.
boolean debugEnabled = logger.isDebugEnabled(); if (definition == null) {
// Use defaults if no transaction definition given.
definition = new DefaultTransactionDefinition();
} if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(definition, transaction, debugEnabled);
} // Check definition settings for new transaction.
if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
} // No existing transaction found -> check propagation behavior to find out how to proceed.
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
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);
//调用具体TransactionManager开启事务的方法
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException ex) {
resume(null, suspendedResources);
throw ex;
}
catch (Error err) {
resume(null, suspendedResources);
throw err;
}
}
else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
}
}
getTransaction方法中
//调用具体TransactionManager开启事务的方法
doBegin(transaction, definition);
跟进其源代码:
ClassHibernateTransactionManager
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction; if (txObject.hasConnectionHolder() && !txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
throw new IllegalTransactionStateException(
"Pre-bound JDBC Connection found! HibernateTransactionManager does not support " +
"running within DataSourceTransactionManager if told to manage the DataSource itself. " +
"It is recommended to use a single HibernateTransactionManager for all transactions " +
"on a single DataSource, no matter whether Hibernate or JDBC access.");
} Session session = null; try {
if (txObject.getSessionHolder() == null || txObject.getSessionHolder().isSynchronizedWithTransaction()) {
Interceptor entityInterceptor = getEntityInterceptor();
Session newSession = (entityInterceptor != null ?
getSessionFactory().openSession(entityInterceptor) : getSessionFactory().openSession());
if (logger.isDebugEnabled()) {
logger.debug("Opened new Session [" + SessionFactoryUtils.toString(newSession) +
"] for Hibernate transaction");
}
txObject.setSession(newSession);
} session = txObject.getSessionHolder().getSession(); if (this.prepareConnection && isSameConnectionForEntireSession(session)) {
// We're allowed to change the transaction settings of the JDBC Connection.
if (logger.isDebugEnabled()) {
logger.debug(
"Preparing JDBC Connection of Hibernate Session [" + SessionFactoryUtils.toString(session) + "]");
}
Connection con = session.connection();
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
}
else {
// Not allowed to change the transaction settings of the JDBC Connection.
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
// We should set a specific isolation level but are not allowed to...
throw new InvalidIsolationLevelException(
"HibernateTransactionManager is not allowed to support custom isolation levels: " +
"make sure that its 'prepareConnection' flag is on (the default) and that the " +
"Hibernate connection release mode is set to 'on_close' (SpringTransactionFactory's default). " +
"Make sure that your LocalSessionFactoryBean actually uses SpringTransactionFactory: Your " +
"Hibernate properties should *not* include a 'hibernate.transaction.factory_class' property!");
}
if (logger.isDebugEnabled()) {
logger.debug(
"Not preparing JDBC Connection of Hibernate Session [" + SessionFactoryUtils.toString(session) + "]");
}
} if (definition.isReadOnly() && txObject.isNewSession()) {
// Just set to NEVER in case of a new Session for this transaction.
session.setFlushMode(FlushMode.MANUAL);
} if (!definition.isReadOnly() && !txObject.isNewSession()) {
// We need AUTO or COMMIT for a non-read-only transaction.
FlushMode flushMode = session.getFlushMode();
if (flushMode.lessThan(FlushMode.COMMIT)) {
session.setFlushMode(FlushMode.AUTO);
txObject.getSessionHolder().setPreviousFlushMode(flushMode);
}
} Transaction hibTx; // Register transaction timeout.
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
// Use Hibernate's own transaction timeout mechanism on Hibernate 3.1+
// Applies to all statements, also to inserts, updates and deletes!
hibTx = session.getTransaction();
hibTx.setTimeout(timeout);
hibTx.begin();
}
else {
// Open a plain Hibernate transaction without specified timeout.
hibTx = session.beginTransaction();
} // Add the Hibernate transaction to the session holder.
txObject.getSessionHolder().setTransaction(hibTx); // Register the Hibernate Session's JDBC Connection for the DataSource, if set.
if (getDataSource() != null) {
Connection con = session.connection();
ConnectionHolder conHolder = new ConnectionHolder(con);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
conHolder.setTimeoutInSeconds(timeout);
}
if (logger.isDebugEnabled()) {
logger.debug("Exposing Hibernate transaction as JDBC transaction [" + con + "]");
}
TransactionSynchronizationManager.bindResource(getDataSource(), conHolder);
txObject.setConnectionHolder(conHolder);
} // Bind the session holder to the thread.
if (txObject.isNewSessionHolder()) {
TransactionSynchronizationManager.bindResource(getSessionFactory(), txObject.getSessionHolder());
}
txObject.getSessionHolder().setSynchronizedWithTransaction(true);
} catch (Exception ex) {
if (txObject.isNewSession()) {
try {
if (session.getTransaction().isActive()) {
session.getTransaction().rollback();
}
}
catch (Throwable ex2) {
logger.debug("Could not rollback Session after failed transaction begin", ex);
}
finally {
SessionFactoryUtils.closeSession(session);
}
}
throw new CannotCreateTransactionException("Could not open Hibernate Session for transaction", ex);
}
}
Spring 源代码阅读之声明式事务的更多相关文章
- spring boot中的声明式事务管理及编程式事务管理
这几天在做一个功能,具体的情况是这样的: 项目中原有的几个功能模块中有数据上报的功能,现在需要在这几个功能模块的上报之后生成一条消息记录,然后入库,在写个接口供前台来拉取消息记录. 看到这个需求,首先 ...
- 八、Spring之深入理解声明式事务
Spring之深入理解声明式事务 何为事务? 事务就是把一系列的动作当成一个独立的工作单元,这些动作要么全部完成,要么全部不起作用. 事务的四个属性: 1.原子性(atomicity) 事务是原子性操 ...
- spring基于xml的声明式事务控制配置步骤
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...
- spring学习08(声明式事务)
11.声明式事务 11.1 回顾事务 事务在项目开发过程非常重要,涉及到数据的一致性的问题,不容马虎! 事务管理是企业级应用程序开发中必备技术,用来确保数据的完整性和一致性. 事务就是把一系列的动作当 ...
- spring事物配置,声明式事务管理和基于@Transactional注解的使用
http://blog.csdn.net/bao19901210/article/details/41724355 http://www.cnblogs.com/leiOOlei/p/3725911. ...
- Spring第13篇—–Spring整合Hibernate之声明式事务管理
不容置疑的我们可以知道Spring的事务管理是通过AOP(AOP把我们的事务管理织入到我们的业务逻辑里面了)的方式来实现的,因为事务方面的代码与spring的绑定并以一种样板式结构使用.(面向切面编程 ...
- spring基于XML的声明式事务控制
<?xml version="1.0" encoding="utf-8" ?><beans xmlns="http://www.sp ...
- Spring(十五)之声明式事务
声明式事务管理方法允许你在配置的帮助下而不是源代码硬编程来管理事务.这意味着你可以将事务管理从事务代码中隔离出来.你可以只使用注释或基于配置的 XML 来管理事务. bean 配置会指定事务型方法.下 ...
- Spring学习笔记:声明式事务管理增删改查业务
一.关于是事务 以方法为单位,进行事务控制:抛出异常,事务回滚. 最小的执行单位为方法.决定执行成败是通过是否抛出异常来判断的,抛出异常即执行失败 二.声明式事务: 声明式事务(declarative ...
随机推荐
- CSS3完善和模式
CSS3改善了传统盒模型架构,增强盒子构成要素的功能,扩展了盒模型显示的方式,具体描述如下 改善构造:除了传统的内容区域,边框区,补白区和边界区外,为盒子新增了轮廓区. 增强功能:内容增强CSS自动添 ...
- 解决部分小程序无法获取UnionId的问题
问题背景 通过观察数据,发现有一部分用户是无法获取到UnionId的 也就是接口返回的参数中不包含UnionId参数 看了微信文档的解释,只要小程序在开放平台绑定,就一定会分配UnionId 网上也有 ...
- thinkphp 查询单个“年-月-日” FROM_UNIXTIME
*时间格式转换,使datetimepicker.js 能够搜索 查询 单个 年月日而不需是区间 查询. //另起一行看转换结果 select *,FROM_UNIXTIME(CreateTime,'% ...
- C# 的逻辑运算
&.^.!和|操作符称为逻辑操作符,用逻辑操作符把运算对象连接起来符合C#语法的式子称为逻辑表达式.逻辑 操作符“!”和“^”只作用于其后的操作数,故称为一元操作符.而“&&” ...
- git分支简介,理解HEAD,master
为了真正理解 Git 处理分支的方式,我们需要回顾一下 Git 是如何保存数据的. 或许你还记得 起步 的内容,Git 保存的不是文件的变化或者差异,而是一系列不同时刻的文件快照. 在进行提交操作时, ...
- 撩课-Web大前端每天5道面试题-Day17
1.apply, call和bind有什么区别? 三者都可以把一个函数应用到其他对象上,注意不是自身对象. apply,call是直接执行函数调用,bind是绑定,执行需要再次调用. apply和ca ...
- java类中成员的初始化顺序(一)
类被创建之后的成员的初始化顺序到底是怎么样的? 首先 不考虑继承 package com; public class DemoOne { /** * 关于类的初始化顺序 */ //不考虑继承结构的情况 ...
- 一个简单的DLL生成和测试
DLL文件内容: SKLDll.h #ifndef _SKLDLL_H_#define _SKLDLL_H_ #ifndef DLL_API #define DLL_API extern " ...
- HTML5 Form Data 对象的使用
HTML5 Form Data 对象的使用 MDN: https://developer.mozilla.org/zh-CN/docs/Web/Guide/Using_FormData_Object ...
- UVAlive6807 Túnel de Rata (最小生成树)
题意 题目链接 Sol 神仙题Orz 我们考虑选的边的补集,可以很惊奇的发现,这个补集中的边恰好是原图中的一颗生成树: 并且答案就是所有边权的和减去这个边集中的边的权值: 于是我们只需要求最大生成树就 ...