首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

spring transation源代码研习笔记

2012-11-16 
spring transation源代码研读笔记最近研读了spring的Transaction的源代码,顺便做个笔记,以防时间长了忘记。

spring transation源代码研读笔记

最近研读了spring的Transaction的源代码,顺便做个笔记,以防时间长了忘记。

?

我们知道如果用编码的方式来写spring的事物管理,代码其实是这样子的

?

?

PlatformTransactionManager transactionManager = new xxxTransactionManager();TransactionDefinition transactionDefinition = new DefultTransactionDefinition ();TransactionStatus status = transactionManager .getTransaction(transactionDefinition);try{//business code goes heretransactionManager .commit(status );}catch(Exception){//business code goes here transactionManager .rollback(status );}finally{    ...}

?

?

所以我们的分析起始点是从TransactionStatus status = transactionManager .getTransaction(transactionDefinition); 这一句开始 。?

?

经过查找,这个方法最终是在AbstractPlatformTransactionManager 中实现的,下面我们来看一看这个方法的具体实现,(顺便说一句,其实在spring中,只要以Abstract开头的类其实都是一个模板类,这个模板类的的公用方法都已经实现)

?

打开这个方法,我们可以看见

?

/** * This implementation handles propagation behavior. Delegates to * <code>doGetTransaction</code>, <code>isExistingTransaction</code> * and <code>doBegin</code>. * @see #doGetTransaction * @see #isExistingTransaction * @see #doBegin */public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {Object transaction = doGetTransaction();// 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 {doBegin(transaction, definition);}catch (RuntimeException ex) {resume(null, suspendedResources);throw ex;}catch (Error err) {resume(null, suspendedResources);throw err;}boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);}else {// Create "empty" transaction: no actual transaction, but potentially synchronization.boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);return newTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);}}

?

?

这个方法里的有3个方法是代理到子类里面去实现的 ,他们分别是doGetTransaction ,?isExistingTransaction,doBegin

?

我们一Hibernate作为一个例子来讲解

?

在AbstractPlatformTransactionManager?中,doGetTransaction?是一个抽象函数 :

?

/** * Return a transaction object for the current transaction state. * <p>The returned object will usually be specific to the concrete transaction * manager implementation, carrying corresponding transaction state in a * modifiable fashion. This object will be passed into the other template * methods (e.g. doBegin and doCommit), either directly or as part of a * DefaultTransactionStatus instance. * <p>The returned object should contain information about any existing * transaction, that is, a transaction that has already started before the * current <code>getTransaction</code> call on the transaction manager. * Consequently, a <code>doGetTransaction</code> implementation will usually * look for an existing transaction and store corresponding state in the * returned transaction object. * @return the current transaction object * @throws org.springframework.transaction.CannotCreateTransactionException * if transaction support is not available * @throws TransactionException in case of lookup or system errors * @see #doBegin * @see #doCommit * @see #doRollback * @see DefaultTransactionStatus#getTransaction */protected abstract Object doGetTransaction() throws TransactionException;

?

?

所以这个方法会在他的子类里面实现, 我们可以在?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 [" +SessionFactoryUtils.toString(sessionHolder.getSession()) + "] for Hibernate transaction");}txObject.setSessionHolder(sessionHolder);}else if (this.hibernateManagedSession) {try {Session session = getSessionFactory().getCurrentSession();if (logger.isDebugEnabled()) {logger.debug("Found Hibernate-managed Session [" +SessionFactoryUtils.toString(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 txObject = new HibernateTransactionObject(); 这句话是获取一个Hibernate的事物对象,这个事物对象里面包含什么信息呢,我们打开这个类看看就知道了

?

?

/** * Hibernate transaction object, representing a SessionHolder. * Used as transaction object by HibernateTransactionManager. */private static class HibernateTransactionObject extends JdbcTransactionObjectSupport {private SessionHolder sessionHolder;private boolean newSessionHolder;private boolean newSession;public void setSession(Session session) {this.sessionHolder = new SessionHolder(session);this.newSessionHolder = true;this.newSession = true;}public void setExistingSession(Session session) {this.sessionHolder = new SessionHolder(session);this.newSessionHolder = true;this.newSession = false;}public void setSessionHolder(SessionHolder sessionHolder) {this.sessionHolder = sessionHolder;this.newSessionHolder = false;this.newSession = false;}public SessionHolder getSessionHolder() {return this.sessionHolder;}public boolean isNewSessionHolder() {return this.newSessionHolder;}public boolean isNewSession() {return this.newSession;}public boolean hasSpringManagedTransaction() {return (this.sessionHolder != null && this.sessionHolder.getTransaction() != null);}public boolean hasHibernateManagedTransaction() {return (this.sessionHolder != null && this.sessionHolder.getSession().getTransaction().isActive());}public void setRollbackOnly() {getSessionHolder().setRollbackOnly();if (hasConnectionHolder()) {getConnectionHolder().setRollbackOnly();}}public boolean isRollbackOnly() {return getSessionHolder().isRollbackOnly() ||(hasConnectionHolder() && getConnectionHolder().isRollbackOnly());}}
?

?

?

他有3个属性分别是?private SessionHolder sessionHolder;?private boolean newSessionHolder;private boolean newSession; 最重要一个属性就是?sessionHolder ,我们一看名称就知道他的含义,session的保持者,因为事物的最初的原则就是,在一个session之内才能完成一个事物,所以在事物的整个过程中,我们必须保持这个session的一致;

?

我们在来看看这一句?SessionHolder sessionHolder =

(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());

?

这句话会初始化一个sessionHolder ,要想一看究竟,进入getResource 来看看

?

?

public abstract class TransactionSynchronizationManager {private static final Log logger = LogFactory.getLog(TransactionSynchronizationManager.class);private static final Comparator synchronizationComparator = new OrderComparator();private static final ThreadLocal resources =new NamedThreadLocal("Transactional resources");private static final ThreadLocal synchronizations =new NamedThreadLocal("Transaction synchronizations");private static final ThreadLocal currentTransactionName =new NamedThreadLocal("Current transaction name");private static final ThreadLocal currentTransactionReadOnly =new NamedThreadLocal("Current transaction read-only status");private static final ThreadLocal currentTransactionIsolationLevel =new NamedThreadLocal("Current transaction isolation level");private static final ThreadLocal actualTransactionActive =new NamedThreadLocal("Actual transaction active");//-------------------------------------// Management of transaction-associated resource handles//-------------------------------------/** * Return all resources that are bound to the current thread. * <p>Mainly for debugging purposes. Resource managers should always invoke * <code>hasResource</code> for a specific resource key that they are interested in. * @return a Map with resource keys (usually the resource factory) and resource * values (usually the active resource object), or an empty Map if there are * currently no resources bound * @see #hasResource */public static Map getResourceMap() {Map map = (Map) resources.get();return (map != null ? Collections.unmodifiableMap(map) : Collections.EMPTY_MAP);}/** * Check if there is a resource for the given key bound to the current thread. * @param key the key to check (usually the resource factory) * @return if there is a value bound to the current thread * @see ResourceTransactionManager#getResourceFactory()  */public static boolean hasResource(Object key) {Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);Object value = doGetResource(actualKey);return (value != null);}/** * Retrieve a resource for the given key that is bound to the current thread. * @param key the key to check (usually the resource factory) * @return a value bound to the current thread (usually the active * resource object), or <code>null</code> if none * @see ResourceTransactionManager#getResourceFactory() */public static Object getResource(Object key) {Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);Object value = doGetResource(actualKey);if (value != null && logger.isTraceEnabled()) {logger.trace("Retrieved value [" + value + "] for key [" + actualKey + "] bound to thread [" +Thread.currentThread().getName() + "]");}return value;}/** * Actually check the value of the resource that is bound for the given key. */private static Object doGetResource(Object actualKey) {Map map = (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);value = null;}return value;}/** * Bind the given resource for the given key to the current thread. * @param key the key to bind the value to (usually the resource factory) * @param value the value to bind (usually the active resource object) * @throws IllegalStateException if there is already a value bound to the thread * @see ResourceTransactionManager#getResourceFactory() */public static void bindResource(Object key, Object value) throws IllegalStateException {Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);Assert.notNull(value, "Value must not be null");Map map = (Map) resources.get();// set ThreadLocal Map if none foundif (map == null) {map = new HashMap();resources.set(map);}if (map.put(actualKey, value) != null) {throw new IllegalStateException("Already value [" + map.get(actualKey) + "] for key [" +actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]");}if (logger.isTraceEnabled()) {logger.trace("Bound value [" + value + "] for key [" + actualKey + "] to thread [" +Thread.currentThread().getName() + "]");}}/** * Unbind a resource for the given key from the current thread. * @param key the key to unbind (usually the resource factory) * @return the previously bound value (usually the active resource object) * @throws IllegalStateException if there is no value bound to the thread * @see ResourceTransactionManager#getResourceFactory() */public static Object unbindResource(Object key) throws IllegalStateException {Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);Object value = doUnbindResource(actualKey);if (value == null) {throw new IllegalStateException("No value for key [" + actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]");}return value;}/** * Unbind a resource for the given key from the current thread. * @param key the key to unbind (usually the resource factory) * @return the previously bound value, or <code>null</code> if none bound */public static Object unbindResourceIfPossible(Object key) {Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);return doUnbindResource(actualKey);}/** * Actually remove the value of the resource that is bound for the given key. */private static Object doUnbindResource(Object actualKey) {Map map = (Map) resources.get();if (map == null) {return null;}Object value = map.remove(actualKey);// Remove entire ThreadLocal if empty...if (map.isEmpty()) {resources.set(null);}if (value != null && logger.isTraceEnabled()) {logger.trace("Removed value [" + value + "] for key [" + actualKey + "] from thread [" +Thread.currentThread().getName() + "]");}return value;}//-------------------------------------// Management of transaction synchronizations//-------------------------------------/** * Return if transaction synchronization is active for the current thread. * Can be called before register to avoid unnecessary instance creation. * @see #registerSynchronization */public static boolean isSynchronizationActive() {return (synchronizations.get() != null);}/** * Activate transaction synchronization for the current thread. * Called by a transaction manager on transaction begin. * @throws IllegalStateException if synchronization is already active */public static void initSynchronization() throws IllegalStateException {if (isSynchronizationActive()) {throw new IllegalStateException("Cannot activate transaction synchronization - already active");}logger.trace("Initializing transaction synchronization");synchronizations.set(new LinkedList());}/** * Register a new transaction synchronization for the current thread. * Typically called by resource management code. * <p>Note that synchronizations can implement the * {@link org.springframework.core.Ordered} interface. * They will be executed in an order according to their order value (if any). * @param synchronization the synchronization object to register * @throws IllegalStateException if transaction synchronization is not active * @see org.springframework.core.Ordered */public static void registerSynchronization(TransactionSynchronization synchronization)    throws IllegalStateException {Assert.notNull(synchronization, "TransactionSynchronization must not be null");if (!isSynchronizationActive()) {throw new IllegalStateException("Transaction synchronization is not active");}List synchs = (List) synchronizations.get();synchs.add(synchronization);}/** * Return an unmodifiable snapshot list of all registered synchronizations * for the current thread. * @return unmodifiable List of TransactionSynchronization instances * @throws IllegalStateException if synchronization is not active * @see TransactionSynchronization */public static List getSynchronizations() throws IllegalStateException {if (!isSynchronizationActive()) {throw new IllegalStateException("Transaction synchronization is not active");}List synchs = (List) synchronizations.get();// Sort lazily here, not in registerSynchronization.Collections.sort(synchs, synchronizationComparator);// Return unmodifiable snapshot, to avoid ConcurrentModificationExceptions// while iterating and invoking synchronization callbacks that in turn// might register further synchronizations.return Collections.unmodifiableList(new ArrayList(synchs));}/** * Deactivate transaction synchronization for the current thread. * Called by the transaction manager on transaction cleanup. * @throws IllegalStateException if synchronization is not active */public static void clearSynchronization() throws IllegalStateException {if (!isSynchronizationActive()) {throw new IllegalStateException("Cannot deactivate transaction synchronization - not active");}logger.trace("Clearing transaction synchronization");synchronizations.set(null);}//-------------------------------------// Exposure of transaction characteristics//-------------------------------------/** * Expose the name of the current transaction, if any. * Called by the transaction manager on transaction begin and on cleanup. * @param name the name of the transaction, or <code>null</code> to reset it * @see org.springframework.transaction.TransactionDefinition#getName() */public static void setCurrentTransactionName(String name) {currentTransactionName.set(name);}/** * Return the name of the current transaction, or <code>null</code> if none set. * To be called by resource management code for optimizations per use case, * for example to optimize fetch strategies for specific named transactions. * @see org.springframework.transaction.TransactionDefinition#getName() */public static String getCurrentTransactionName() {return (String) currentTransactionName.get();}/** * Expose a read-only flag for the current transaction. * Called by the transaction manager on transaction begin and on cleanup. * @param readOnly <code>true</code> to mark the current transaction * as read-only; <code>false</code> to reset such a read-only marker * @see org.springframework.transaction.TransactionDefinition#isReadOnly() */public static void setCurrentTransactionReadOnly(boolean readOnly) {currentTransactionReadOnly.set(readOnly ? Boolean.TRUE : null);}/** * Return whether the current transaction is marked as read-only. * To be called by resource management code when preparing a newly * created resource (for example, a Hibernate Session). * <p>Note that transaction synchronizations receive the read-only flag * as argument for the <code>beforeCommit</code> callback, to be able * to suppress change detection on commit. The present method is meant * to be used for earlier read-only checks, for example to set the * flush mode of a Hibernate Session to "FlushMode.NEVER" upfront. * @see org.springframework.transaction.TransactionDefinition#isReadOnly() * @see TransactionSynchronization#beforeCommit(boolean) * @see org.hibernate.Session#flush * @see org.hibernate.Session#setFlushMode * @see org.hibernate.FlushMode#NEVER */public static boolean isCurrentTransactionReadOnly() {return (currentTransactionReadOnly.get() != null);}/** * Expose an isolation level for the current transaction. * Called by the transaction manager on transaction begin and on cleanup. * @param isolationLevel the isolation level to expose, according to the * JDBC Connection constants (equivalent to the corresponding Spring * TransactionDefinition constants), or <code>null</code> to reset it * @see java.sql.Connection#TRANSACTION_READ_UNCOMMITTED * @see java.sql.Connection#TRANSACTION_READ_COMMITTED * @see java.sql.Connection#TRANSACTION_REPEATABLE_READ * @see java.sql.Connection#TRANSACTION_SERIALIZABLE * @see org.springframework.transaction.TransactionDefinition#ISOLATION_READ_UNCOMMITTED * @see org.springframework.transaction.TransactionDefinition#ISOLATION_READ_COMMITTED * @see org.springframework.transaction.TransactionDefinition#ISOLATION_REPEATABLE_READ * @see org.springframework.transaction.TransactionDefinition#ISOLATION_SERIALIZABLE * @see org.springframework.transaction.TransactionDefinition#getIsolationLevel() */public static void setCurrentTransactionIsolationLevel(Integer isolationLevel) {currentTransactionIsolationLevel.set(isolationLevel);}/** * Return the isolation level for the current transaction, if any. * To be called by resource management code when preparing a newly * created resource (for example, a JDBC Connection). * @return the currently exposed isolation level, according to the * JDBC Connection constants (equivalent to the corresponding Spring * TransactionDefinition constants), or <code>null</code> if none * @see java.sql.Connection#TRANSACTION_READ_UNCOMMITTED * @see java.sql.Connection#TRANSACTION_READ_COMMITTED * @see java.sql.Connection#TRANSACTION_REPEATABLE_READ * @see java.sql.Connection#TRANSACTION_SERIALIZABLE * @see org.springframework.transaction.TransactionDefinition#ISOLATION_READ_UNCOMMITTED * @see org.springframework.transaction.TransactionDefinition#ISOLATION_READ_COMMITTED * @see org.springframework.transaction.TransactionDefinition#ISOLATION_REPEATABLE_READ * @see org.springframework.transaction.TransactionDefinition#ISOLATION_SERIALIZABLE * @see org.springframework.transaction.TransactionDefinition#getIsolationLevel() */public static Integer getCurrentTransactionIsolationLevel() {return (Integer) currentTransactionIsolationLevel.get();}/** * Expose whether there currently is an actual transaction active. * Called by the transaction manager on transaction begin and on cleanup. * @param active <code>true</code> to mark the current thread as being associated * with an actual transaction; <code>false</code> to reset that marker */public static void setActualTransactionActive(boolean active) {actualTransactionActive.set(active ? Boolean.TRUE : null);}/** * Return whether there currently is an actual transaction active. * This indicates whether the current thread is associated with an actual * transaction rather than just with active transaction synchronization. * <p>To be called by resource management code that wants to discriminate * between active transaction synchronization (with or without backing * resource transaction; also on PROPAGATION_SUPPORTS) and an actual * transaction being active (with backing resource transaction; * on PROPAGATION_REQUIRES, PROPAGATION_REQUIRES_NEW, etc). * @see #isSynchronizationActive() */public static boolean isActualTransactionActive() {return (actualTransactionActive.get() != null);}/** * Clear the entire transaction synchronization state for the current thread: * registered synchronizations as well as the various transaction characteristics. * @see #clearSynchronization() * @see #setCurrentTransactionName * @see #setCurrentTransactionReadOnly * @see #setCurrentTransactionIsolationLevel * @see #setActualTransactionActive */public static void clear() {clearSynchronization();setCurrentTransactionName(null);setCurrentTransactionReadOnly(false);setCurrentTransactionIsolationLevel(null);setActualTransactionActive(false);}}
?

?

我们发现这个类里面有很多的ThreadLocal 对象,关于TreadLocal的作用这里不做解释,不懂的可以上网查阅;

简言之 ?:TreadLocal就是线程局部变量,在整个线程存活期间,可以随时访问该变量,当线程死亡自后,该变量也会随着线程一起死亡,最后由被GC回收。所以我们的sessionHolder是和线程绑定在一起的,所以在线程存活期间,可以随时得到这个sessionHolder,进而取得数据库的session。

?

?

?

接下来,我们看看?public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException 的doBegin(transaction, definition);

他也是个抽象函数,也是在子类里面实现 我们来看看Hibernate的的这个实现方法

?

?

?

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.NEVER);}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 = null;// 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);}}

?

?

这个方法里面是从sessionHolder中获取session 然后hibTx = session.getTransaction();

hibTx.setTimeout(timeout);

hibTx.begin();

?

我觉得如果你对Hibernate的事物很熟悉,我想不用解释你就可以了解这是干什么,这个上就是获取Hibernate的自身的事物Transaction。到此,事物开始;

?

我们在看看事物的提交 ?

?

?

ransactionManager .commit(status );

?

?

?

/** * This implementation of commit handles participating in existing * transactions and programmatic rollback requests. * Delegates to <code>isRollbackOnly</code>, <code>doCommit</code> * and <code>rollback</code>. * @see org.springframework.transaction.TransactionStatus#isRollbackOnly() * @see #doCommit * @see #rollback */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);return;}if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {if (defStatus.isDebug()) {logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");}processRollback(defStatus);// Throw UnexpectedRollbackException only at outermost transaction boundary// or if explicitly asked to.if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {throw new UnexpectedRollbackException("Transaction rolled back because it has been marked as rollback-only");}return;}processCommit(defStatus);}

我们看到一句processCommit(defStatus)

?

?

/** * Process an actual commit. * Rollback-only flags have already been checked and applied. * @param status object representing the transaction * @throws TransactionException in case of commit failure */private void processCommit(DefaultTransactionStatus status) throws TransactionException {try {boolean beforeCompletionInvoked = false;try {prepareForCommit(status);triggerBeforeCommit(status);triggerBeforeCompletion(status);beforeCompletionInvoked = true;boolean globalRollbackOnly = false;if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {globalRollbackOnly = status.isGlobalRollbackOnly();}if (status.hasSavepoint()) {if (status.isDebug()) {logger.debug("Releasing transaction savepoint");}status.releaseHeldSavepoint();}else if (status.isNewTransaction()) {if (status.isDebug()) {logger.debug("Initiating transaction commit");}doCommit(status);}// Throw UnexpectedRollbackException if we have a global rollback-only// marker but still didn't get a corresponding exception from commit.if (globalRollbackOnly) {throw new UnexpectedRollbackException("Transaction silently rolled back because it has been marked as rollback-only");}}catch (UnexpectedRollbackException ex) {// can only be caused by doCommittriggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);throw ex;}catch (TransactionException ex) {// can only be caused by doCommitif (isRollbackOnCommitFailure()) {doRollbackOnCommitException(status, ex);}else {triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);}throw ex;}catch (RuntimeException ex) {if (!beforeCompletionInvoked) {triggerBeforeCompletion(status);}doRollbackOnCommitException(status, ex);throw ex;}catch (Error err) {if (!beforeCompletionInvoked) {triggerBeforeCompletion(status);}doRollbackOnCommitException(status, err);throw err;}// Trigger afterCommit callbacks, with an exception thrown there// propagated to callers but the transaction still considered as committed.try {triggerAfterCommit(status);}finally {triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);}}finally {cleanupAfterCompletion(status);}}

?

看到doCommit(status); 方法没有,这个方法也是在子类里面实现的我们来看看hibernate里面的具体实现

?

?

protected void doCommit(DefaultTransactionStatus status) {HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();if (status.isDebug()) {logger.debug("Committing Hibernate transaction on Session [" +SessionFactoryUtils.toString(txObject.getSessionHolder().getSession()) + "]");}try {txObject.getSessionHolder().getTransaction().commit();}catch (org.hibernate.TransactionException ex) {// assumably from commit call to the underlying JDBC connectionthrow new TransactionSystemException("Could not commit Hibernate transaction", ex);}catch (HibernateException ex) {// assumably failed to flush changes to databasethrow convertHibernateAccessException(ex);}}
?

看到?txObject.getSessionHolder().getTransaction().commit(); 我们就明白了

?

而rollback是在?protected void doRollback(DefaultTransactionStatus status) {

HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();if (status.isDebug()) {logger.debug("Rolling back Hibernate transaction on Session [" +SessionFactoryUtils.toString(txObject.getSessionHolder().getSession()) + "]");}try {txObject.getSessionHolder().getTransaction().rollback();}catch (org.hibernate.TransactionException ex) {throw new TransactionSystemException("Could not roll back Hibernate transaction", ex);}catch (HibernateException ex) {// Shouldn't really happen, as a rollback doesn't cause a flush.throw convertHibernateAccessException(ex);}finally {if (!txObject.isNewSession() && !this.hibernateManagedSession) {// Clear all pending inserts/updates/deletes in the Session.// Necessary for pre-bound Sessions, to avoid inconsistent state.txObject.getSessionHolder().getSession().clear();}}}
?

这个方法里面实现的 ?

?

txObject.getSessionHolder().getTransaction().rollback();

?

spring其实最终调用的hibernate的本事事物管理来进行事物的提交和回滚的,其实类型的事物都是按照这个模板来写的例如 ? jdbc ?,jdo 等等

热点排行