Spring事务
Spring的事务有编程式事务和声明式事务两种。Spring的事务实现都在spring-tx包。
编程式事务
先附上代码再分析。
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private DruidDataSource dataSource;//数据源
@Autowired
private AccountDao accountDao;//持久层
@Override
public void update(String OutName, String InName, double money) {
PlatformTransactionManager pm =null;
TransactionStatus ts =null;
try {
pm = new DataSourceTransactionManager(dataSource);
TransactionDefinition td = new DefaultTransactionDefinition();
ts = pm.getTransaction(td);
accountDao.inMoney("张三",100.0);//张三加100块钱
// int i=1/0;
accountDao.outMoney("李四", 100.0);//李四减去100块钱
pm.commit(ts);
} catch (TransactionException e) {
if (pm!=null){
pm.rollback(ts);
}
}
}
}
以上代码模拟转账操作。我们通过上述代码来进行分析。
源码分析
1.初始化PlatformTransactionManager
PlatformTransactionManager pm =new DataSourceTransactionManager(dataSource);
此处创建了一个DataSourceTransactionManager对象,dataSource是数据源,点进去看源码。
public DataSourceTransactionManager() {
//调用了父类的setNestedTransactionAllowed方法
setNestedTransactionAllowed(true);
}
public DataSourceTransactionManager(DataSource dataSource) {
//此处调用了上面的构造方法
this();
setDataSource(dataSource);
//判断dataSource是否为null
afterPropertiesSet();
}
这是父类的setNestedTransactionAllowed方法 对nestedTransactionAllowed 属性进行了赋值
public final void setNestedTransactionAllowed(boolean nestedTransactionAllowed) {
//设置为可嵌套事务
this.nestedTransactionAllowed = nestedTransactionAllowed;
}
到了此处PlatformTransactionManager初始化完成。
2.初始化TransactionDefinition
TransactionDefinition td = new DefaultTransactionDefinition();
DefaultTransactionDefinition有两个构造方法我们此处用的第一个,第二个构造方法可以看出是将别的TransactionDefinition的实现属性进行赋值。DefaultTransactionDefinition里的属性对事务进行了描述,例如事务的隔离级别,传播途径,超时时间等等。
public DefaultTransactionDefinition() {
}
public DefaultTransactionDefinition(TransactionDefinition other) {
this.propagationBehavior = other.getPropagationBehavior();
this.isolationLevel = other.getIsolationLevel();
this.timeout = other.getTimeout();
this.readOnly = other.isReadOnly();
this.name = other.getName();
}
TransactionDefinition初始化完成。
接下来获取事务当前状态
3.getTransaction方法
TransactionStatus ts = pm.getTransaction(td);
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
//创建了DataSourceTransactionObject对象
Object transaction = doGetTransaction();
boolean debugEnabled = logger.isDebugEnabled();
//如果definition为空此处会创建一个新的
if (definition == null) {
definition = new DefaultTransactionDefinition();
}
//判断是否有现有的事务,内部也是通过ConnectionHolder判断
if (isExistingTransaction(transaction)) {
return handleExistingTransaction(definition, transaction, debugEnabled);
}
// 检查事务的超时时间
if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
}
// 此处获取当前事务的传播行为,走到这里意味着当前线程没有事务所以抛异常
//PROPAGATION_MANDATORY当前存在事务则加入不存在则抛异常
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) {
//挂起事务的方法,此处参数为null就不进行挂起操作,对于有些传播途径会需要挂起操作,实际上的挂起操作就是将他从ThreadLocal中取出来然后放到一个SuspendedResourcesHolder对象中
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
}
try {
//此处与事务同步有关,根据newSynchronization属性来判断是否需要事务同步
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
//创建了DefaultTransactionStatus对象
DefaultTransactionStatus status = newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
//开启事务,并设置事务的一些属性只读 超时时间 隔离级别等
doBegin(transaction, definition);
//将status 和 definition中的属性赋值给TransactionSynchronizationManager(为了保证线程安全用的ThreadLocal维护connection)
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException | Error ex) {
resume(null, suspendedResources);
throw ex;
}
}
else {
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated; " +
"isolation level will effectively be ignored: " + definition);
}
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
}
}
doGetTransaction方法创建了DataSourceTransactionObject对象
protected Object doGetTransaction() {
//创建了DataSourceTransactionObject对象
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
//此处与嵌套事务有关,默认初始化Manager的时候已经赋值为true 所以此处也为true 嵌套事务的实现也需要靠SavePoint
txObject.setSavepointAllowed(isNestedTransactionAllowed());
//判断当前线程有没有连接
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
//有的话可以进行复用
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
doBegin方法开启了事务
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
//此处还是判断如果当前线程没有连接则新获取一个
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
//获取连接
Connection newCon = obtainDataSource().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
//将获取到的设置到ConnectionHolder属性
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
//设置连接的SynchronizedWithTransaction事务同步属性为true
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
//获取连接
con = txObject.getConnectionHolder().getConnection();
//prepareConnectionForTransaction方法根据definition中对事务的描述,对connection的只读属性和事务的隔离级别进行了赋值,返回来的是事务的隔离级别。此处源码可以自己看一下。如果definition没有对属性进行赋值,则返回的是null,connection的隔离级别默认为REPEATABLE_READ
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
//设置事务的隔离级别
txObject.setPreviousIsolationLevel(previousIsolationLevel);
//设置只读属性
txObject.setReadOnly(definition.isReadOnly());
//此处是开启事务,JDBC开启事务就是要设置AutoCommit为false
if (con.getAutoCommit()) {
//这个属性为了恢复autoCommit属性后面会用到 用来判断是否设置AutoCommit为true
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
//开启事务
con.setAutoCommit(false);
}
//这个方法主要执行了一句SQL SET TRANSACTION READ ONLY 如果definition中为只读那么就执行SQL 设置事务为只读
prepareTransactionalConnection(con, definition);
txObject.getConnectionHolder().setTransactionActive(true);
//这个方法返回了definition中的超时时间
int timeout = determineTimeout(definition);
//如果与默认的不同,则设置给connect
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
//先进行判断是新创建的连接就绑定
if (txObject.isNewConnectionHolder()) {
//该方法内部有ThreadLoacl把连接放到ThreadLoacl中与当前线程绑定
TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
}
}
catch (Throwable ex) {
//如果出异常则释放资源,并且设置ConnectionHolder为null
if (txObject.isNewConnectionHolder()) {
DataSourceUtils.releaseConnection(con, obtainDataSource());
txObject.setConnectionHolder(null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}
4.commit
中间执行完逻辑执行commit方法,我们来看看commit方法的实现
@Override
public final void commit(TransactionStatus status) throws TransactionException {
//判断事务是否已经提交,防止重复提交
if (status.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
//判断事务是否设置为回滚状态
if (defStatus.isLocalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Transactional code has requested rollback");
}
processRollback(defStatus, false);
return;
}
//shouldCommitOnGlobalRollbackOnly默认返回false isGlobalRollbackOnly与嵌套事务有关,此处先不讨论
if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
}
processRollback(defStatus, true);
return;
}
//提交事务的逻辑
processCommit(defStatus);
}
processCommit方法
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
boolean beforeCompletionInvoked = false;
try {
boolean unexpectedRollback = false;
//提交事务前的处理,这个事务没有子类实现,父类也是空,暂时没啥用
prepareForCommit(status);
//事务提交前的处理
triggerBeforeCommit(status);
triggerBeforeCompletion(status);
beforeCompletionInvoked = true;
//判断是否有回滚点,此处先不讨论
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Releasing transaction savepoint");
}
unexpectedRollback = status.isGlobalRollbackOnly();
status.releaseHeldSavepoint();
}
//除非是新事务才会提交
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction commit");
}
unexpectedRollback = status.isGlobalRollbackOnly();
//具体的提交事务,数据库层面
doCommit(status);
}
else if (isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = status.isGlobalRollbackOnly();
}
if (unexpectedRollback) {
throw new UnexpectedRollbackException(
"Transaction silently rolled back because it has been marked as rollback-only");
}
}
catch (UnexpectedRollbackException ex) {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
throw ex;
}
catch (TransactionException ex) {
if (isRollbackOnCommitFailure()) {
doRollbackOnCommitException(status, ex);
}
else {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
}
throw ex;
}
catch (RuntimeException | Error ex) {
if (!beforeCompletionInvoked) {
triggerBeforeCompletion(status);
}
doRollbackOnCommitException(status, ex);
throw ex;
}
try {
//提交事务后的钩子方法
triggerAfterCommit(status);
}
finally {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
}
}
finally {
cleanupAfterCompletion(status);
}
}
doCommit方法
protected void doCommit(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Committing JDBC transaction on Connection [" + con + "]");
}
try {
con.commit();
}
catch (SQLException ex) {
throw new TransactionSystemException("Could not commit JDBC transaction", ex);
}
}
5.rollback
public final void rollback(TransactionStatus status) throws TransactionException {
if (status.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
processRollback(defStatus, false);
}
processRollback方法
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
try {
boolean unexpectedRollback = unexpected;
try {
triggerBeforeCompletion(status);
//判断是否有回滚点 与嵌套事务有关 此处先不讨论
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Rolling back transaction to savepoint");
}
status.rollbackToHeldSavepoint();
}
//如果是新事务
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction rollback");
}
//事务回滚
doRollback(status);
}
else {
if (status.hasTransaction()) {
if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
if (status.isDebug()) {
logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
}
doSetRollbackOnly(status);
}
else {
if (status.isDebug()) {
logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
}
}
}
else {
logger.debug("Should roll back transaction but cannot - no transaction available");
}
if (!isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = false;
}
}
}
catch (RuntimeException | Error ex) {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw ex;
}
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
if (unexpectedRollback) {
throw new UnexpectedRollbackException(
"Transaction rolled back because it has been marked as rollback-only");
}
}
finally {
//释放资源 此处就会用到之前的一个属性 用来恢复autoCommit的状态
cleanupAfterCompletion(status);
}
}
doRollback方法
@Override
protected void doRollback(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
}
try {
con.rollback();
}
catch (SQLException ex) {
throw translateException("JDBC rollback", ex);
}
}
整体流程大致就是这样,暂时还没有看具体的嵌套事务的流程等等。仅仅是常规的一个流程,后面再慢慢挖掘
总结
Spring的编程式事务通过PlatformTransactionManager接口来管理
public interface PlatformTransactionManager extends TransactionManager {
TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
我们可以看到PlatformTransactionManager接口里面定义了三个方法,获取事务状态,提交事务,回滚事务三个方法。
通过TransactionStatus来描述事务的状态
public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {
boolean hasSavepoint();//判断是否有回滚点
@Override
void flush();//暂时不知道这个刷新是刷新什么
}
接下来是TransactionDefinition,这个接口主要是对事务的定义。例如传播行为,隔离级别等等。
public interface TransactionDefinition {
int PROPAGATION_REQUIRED = 0;
int PROPAGATION_SUPPORTS = 1;
int PROPAGATION_MANDATORY = 2;
int PROPAGATION_REQUIRES_NEW = 3;
int PROPAGATION_NOT_SUPPORTED = 4;
int PROPAGATION_NEVER = 5;
int PROPAGATION_NESTED = 6;
int ISOLATION_DEFAULT = -1;
int ISOLATION_READ_UNCOMMITTED = 1;
int ISOLATION_READ_COMMITTED = 2;
int ISOLATION_REPEATABLE_READ = 4;
int ISOLATION_SERIALIZABLE = 8;
int TIMEOUT_DEFAULT = -1;
default int getPropagationBehavior() {
return PROPAGATION_REQUIRED;
}
default int getIsolationLevel() {
return ISOLATION_DEFAULT;
}
default int getTimeout() {
return TIMEOUT_DEFAULT;
}
default boolean isReadOnly() {
return false;
}
@Nullable
default String getName() {
return null;
}
static TransactionDefinition withDefaults() {
return StaticTransactionDefinition.INSTANCE;
}
}
不同的框架通过这三个接口来实现他们各自的事务
以上均为个人理解,如果有错误,请大佬指出。谢谢。