org.jfaster.mango.transaction.TransactionImpl Maven / Gradle / Ivy
/*
* Copyright 2014 mango.jfaster.org
*
* The Mango Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.jfaster.mango.transaction;
import org.jfaster.mango.transaction.exception.IllegalTransactionStateException;
import org.jfaster.mango.transaction.exception.TransactionSystemException;
import org.jfaster.mango.util.logging.InternalLogger;
import org.jfaster.mango.util.logging.InternalLoggerFactory;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
/**
* @author ash
*/
public class TransactionImpl implements Transaction {
private final static InternalLogger logger = InternalLoggerFactory.getInstance(TransactionImpl.class);
private final boolean newTransaction;
private final DataSource dataSource;
private final Integer previousLevel;
private final boolean mustRestoreAutoCommit;
private boolean completed = false;
private boolean rollbackOnly = false;
public TransactionImpl(boolean newTransaction, DataSource dataSource) {
this(newTransaction, dataSource, null, true);
}
public TransactionImpl(boolean newTransaction, DataSource dataSource,
Integer previousLevel, boolean mustRestoreAutoCommit) {
this.newTransaction = newTransaction;
this.dataSource = dataSource;
this.previousLevel = previousLevel;
this.mustRestoreAutoCommit = mustRestoreAutoCommit;
}
@Override
public void commit() {
if (completed) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
ConnectionHolder connHolder = TransactionSynchronizationManager.getConnectionHolder(dataSource);
if (connHolder == null) {
throw new IllegalStateException("No ConnectionHolder bind to DataSource [" + dataSource + "]");
}
if (!newTransaction) { // 嵌套的事务,不真正提交
if (logger.isDebugEnabled()) {
logger.debug("Commit transaction is not new");
}
if (rollbackOnly) {
if (logger.isDebugEnabled()) {
logger.debug("Marking transaction as rollback-only");
}
connHolder.setRollbackOnly(true); // 促发顶层事务回滚
}
return;
}
if (rollbackOnly || connHolder.isRollbackOnly()) { // 嵌套的事务出现回滚则回滚
if (logger.isDebugEnabled()) {
logger.debug("Transaction is marked as rollback-only, so will rollback");
}
processRollback(connHolder.getConnection());
return;
}
// 提交事务
processCommit(connHolder.getConnection());
}
@Override
public void rollback() {
if (completed) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
ConnectionHolder connHolder = TransactionSynchronizationManager.getConnectionHolder(dataSource);
if (connHolder == null) {
throw new IllegalStateException("No ConnectionHolder bind to DataSource [" + dataSource + "]");
}
if (!newTransaction) {
if (logger.isDebugEnabled()) {
logger.debug("Rollback transaction is not new, marking transaction as rollback-only");
}
connHolder.setRollbackOnly(true); // 促发顶层事务回滚
return;
}
processRollback(connHolder.getConnection());
}
@Override
public boolean isRollbackOnly() {
return rollbackOnly;
}
@Override
public void setRollbackOnly(boolean rollbackOnly) {
this.rollbackOnly = rollbackOnly;
}
private void processCommit(Connection conn) {
try {
doCommit(conn);
} catch (Exception e) {
doRollbackOnCommitException(conn, e);
} finally {
cleanup(conn);
}
}
private void doCommit(Connection conn) {
try {
if (logger.isDebugEnabled()) {
logger.debug("Committing JDBC transaction on Connection [" + conn + "]");
}
conn.commit();
} catch (SQLException e) {
throw new TransactionSystemException("Could not commit JDBC transaction", e);
}
}
private void doRollbackOnCommitException(Connection conn, Exception e) {
try {
doRollback(conn);
} catch (TransactionSystemException tes) {
logger.error("Commit exception overridden by rollback exception", e);
throw tes;
}
}
private void processRollback(Connection conn) {
try {
doRollback(conn);
} finally {
cleanup(conn);
}
}
private void doRollback(Connection conn) {
try {
if (logger.isDebugEnabled()) {
logger.debug("Rolling back JDBC transaction on Connection [" + conn + "]");
}
conn.rollback();
} catch (SQLException e) {
throw new TransactionSystemException("Could not roll back JDBC transaction", e);
}
}
private void cleanup(Connection conn) {
TransactionSynchronizationManager.unbindConnectionHolder(dataSource);
resetConnectionAfterTransaction(conn);
DataSourceUtils.releaseConnection(conn, dataSource);
completed = true;
}
private void resetConnectionAfterTransaction(Connection conn) {
try {
if (mustRestoreAutoCommit) {
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection to auto commit");
}
conn.setAutoCommit(true);
}
} catch (SQLException e) {
DataSourceMonitor.resetAutoCommitFail(dataSource);
logger.error("Could not reset autoCommit of JDBC Connection after transaction", e);
} catch (Throwable e) {
DataSourceMonitor.resetAutoCommitFail(dataSource);
logger.error("Unexpected exception on resetting autoCommit of JDBC Connection after transaction", e);
}
try {
if (previousLevel != null) {
if (logger.isDebugEnabled()) {
logger.debug("Resetting isolation level of JDBC Connection to " + previousLevel);
}
conn.setTransactionIsolation(previousLevel);
}
} catch (SQLException e) {
logger.error("Could not reset isolation level of JDBC Connection after transaction", e);
} catch (Throwable e) {
logger.error("Unexpected exception on resetting isolation level of JDBC Connection after transaction", e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy