package com.ctrip.platform.dal.dao.client; import java.sql.SQLException; import java.util.List; import java.util.Objects; import com.ctrip.platform.dal.dao.DalEventEnum; import com.ctrip.platform.dal.dao.DalHints; import com.ctrip.platform.dal.dao.markdown.MarkdownManager; import com.ctrip.platform.dal.exceptions.DalException; import com.ctrip.platform.dal.exceptions.ErrorCode; public class DalTransactionManager { private DalConnectionManager connManager; private static final ThreadLocal<DalTransaction> transactionHolder = new ThreadLocal<DalTransaction>(); public DalTransactionManager(DalConnectionManager connManager) { this.connManager = connManager; } private int startTransaction(DalHints hints, DalEventEnum operation) throws SQLException { DalTransaction transaction = transactionHolder.get(); if(transaction == null) { transaction = new DalTransaction( getConnection(hints, true, operation), connManager.getLogicDbName()); transactionHolder.set(transaction); } return transaction.startTransaction(); } private void endTransaction(int startLevel) throws SQLException { DalTransaction transaction = transactionHolder.get(); if(transaction == null) throw new SQLException("calling endTransaction with empty ConnectionCache"); transaction.endTransaction(startLevel); } public static boolean isInTransaction() { return transactionHolder.get() != null; } private static void reqiresTransaction() throws DalException { if(!isInTransaction()) throw new DalException(ErrorCode.TransactionNoFound); } public static List<DalTransactionListener> getCurrentListeners() throws DalException { reqiresTransaction(); return transactionHolder.get().getListeners(); } public static void register(DalTransactionListener listener) throws DalException { reqiresTransaction(); Objects.requireNonNull(listener, "The listener should not be null"); transactionHolder.get().register(listener); } private void rollbackTransaction() throws SQLException { DalTransaction transaction = transactionHolder.get(); // Already handled in deeper level if(transaction == null) return; transaction.rollbackTransaction(); } public DalConnection getConnection(DalHints hints, DalEventEnum operation) throws SQLException { return getConnection(hints, false, operation); } public static String getLogicDbName() { return isInTransaction() ? transactionHolder.get().getLogicDbName() : null; } public static DbMeta getCurrentDbMeta() { return isInTransaction() ? transactionHolder.get().getConnection().getMeta() : null; } private DalConnection getConnection(DalHints hints, boolean useMaster, DalEventEnum operation) throws SQLException { DalTransaction transaction = transactionHolder.get(); if(transaction == null) { return connManager.getNewConnection(hints, useMaster, operation); } else { transaction.validate(connManager.getLogicDbName()); return transaction.getConnection(); } } public static void clearCurrentTransaction() { transactionHolder.set(null); } public <T> T doInTransaction(ConnectionAction<T> action, DalHints hints)throws SQLException{ action.initLogEntry(connManager.getLogicDbName(), hints); action.start(); Throwable ex = null; T result = null; int level; try { level = startTransaction(hints, action.operation); action.populateDbMeta(); result = action.execute(); endTransaction(level); } catch (Throwable e) { ex = e; rollbackTransaction(); MarkdownManager.detect(action.connHolder, action.start, e); }finally{ action.cleanup(); } action.end(result, ex); return result; } }