- 浏览: 48673 次
- 性别:
- 来自: 成都
最新评论
-
洞中有怪兽:
osworkflow+spring+jdbc实现 -
呵呵呵123:
osuser.xml配置怎么配啊
osworkflow+spring+jdbc实现 -
zhaoyangjay:
你是不是改过JAR包中的源代码了,AbstractWorkfl ...
osworkflow dynamic split 动态会签的实现 -
dingchao.lonton:
TheMatrix 写道有个问题,例子中都是用同一个用户去执行 ...
osworkflow dynamic split 动态会签的实现 -
TheMatrix:
有个问题,例子中都是用同一个用户去执行doAction三遍,现 ...
osworkflow dynamic split 动态会签的实现
spring transation源代码研读笔记
最近研读了spring的Transaction的源代码,顺便做个笔记,以防时间长了忘记。
我们知道如果用编码的方式来写spring的事物管理,代码其实是这样子的
PlatformTransactionManager transactionManager = new xxxTransactionManager(); TransactionDefinition transactionDefinition = new DefultTransactionDefinition (); TransactionStatus status = transactionManager .getTransaction(transactionDefinition); try{ //business code goes here transactionManager .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 found if (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 doCommit triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK); throw ex; } catch (TransactionException ex) { // can only be caused by doCommit if (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 connection throw new TransactionSystemException("Could not commit Hibernate transaction", ex); } catch (HibernateException ex) { // assumably failed to flush changes to database throw 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 等等
相关推荐
里面为一个演示spring事务传播机制的小demo。简单实现转账功能,通过添加注解调整传播级别,同时通过日志打印查看sql是否执行,在mysql中的数据是否发生了变化(操作提交还是回滚了)。
spring-transaction.jar.zip
Spring在Transaction事务传播行为种类,希望对大家有所帮助
详细介绍了Spring 与 IOC,Aop,还有Spring与JDBC,HIBERNATE,STRUTS,Transaction 进行集成,配置文件的编写
12. Spring Transaction Management 13. Spring Batch 14. Spring NoSQL and Big Data 15. Spring Java Enterprise Services and Remoting Technologies 16. Spring Messaging 17. Spring Integration 18. Spring ...
NULL 博文链接:https://wsjjasper.iteye.com/blog/1570448
org.springframework.transaction-3.2.2.RELEASE最新版本
org.springframework.transaction-3.0.0.M4.jar
spring 事务管理工程,导入到MyEclipse 中既可以使用
org.springframework.transaction-3.1.0.M2
Spring中的事务管理问题:org.springframework.transaction-3.1.0.M1.jar包。org.springframework.transaction-3.1.0.M1.jar包。
org.springframework.transaction-3.1.0.M1.jar
org.springframework.transaction-3.2.4.RELEASE.jar,最新版的org.springframework.transaction,Wed Aug 07 16:44:37 GMT+01:00 2013
分布式事务框架LCN支持springcloud 2.0.5 ,transaction-springcloud-4.1.2.jar
spring-hibernate-maven-transaction整合
Spring交易演示spring-transaction-demo spring事务传播机制的7种使用方式
Spring 的核心是个轻量级(Lightweight)的容器(Container),它是实现IoC(Inversion of Control)容器、非侵入性(No intrusive)的框架,并提供AOP(Aspect-oriented programming)概念的实现方式,提供对...
Spring 事务授课代码 声明式事务 事务传播规则 事务隔离机制
java运行依赖jar包
Spring多数据源配置_分布式数据 Tomcat服务器下的多数据源配置详情 一、环境及框架 ...1. <bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean" /> 2、定义数据源 xml 代码