1. 程式人生 > >spring入門詳細教程(五)

spring入門詳細教程(五)

前言

本篇緊接著spring入門詳細教程(三),建議閱讀本篇前,先閱讀第一篇,第二篇以及第三篇。連結如下:

Spring入門詳細教程(一) https://www.cnblogs.com/jichi/p/10165538.html

Spring入門詳細教程(二) https://www.cnblogs.com/jichi/p/10176601.html

Spring入門詳細教程(三) https://www.cnblogs.com/jichi/p/10177004.html

Spring入門詳細教程(四) https://www.cnblogs.com/jichi/p/10211475.html

本篇主要講解spring的事務處理。

一、什麼是事務

事務用白話來說比較好理解,我們舉個例子。比如說你做兩件事要達成一個目的。其中有一件事失敗,你就相當於沒做。如果兩件事都成功,這件事你才算做的成功。用官方話來解釋,就是事務是邏輯上的一組操作,組成這組操作的各個邏輯單元,要麼一起成功,要麼一起失敗。

二、事務的特性

瞭解了事務的概念,我們就可以瞭解事務的特性了。

事務有四大特性:原子性,一致性,隔離性,永續性。

原子性:強調事務的不可分割。

一致性:事務的執行的前後資料的完整性保持一致。

隔離性:一個事務執行的過程中,不應受到其他事務的干擾。

永續性:事務一旦結束,資料就持久到資料庫。

三、事務的併發問題

事務三大問題,髒讀,幻讀,不可重複讀。

髒讀:一個事務讀到了另一個事務的未提交的資料。

不可重複讀:一個事務讀到了另一個事務已經提交的update的資料導致多次查詢結果不一致。

虛幻讀:一個事務讀到了另一個事務已經提交的insert的資料導致多次查詢結果不一致。

四、事務併發問題的解決:事務隔離級別

1、未提交讀:髒讀,不可重複讀,虛幻讀都有可能發生。

2、已提交讀:避免髒讀。不可重複讀和虛幻讀都可能發生。

3、可重複讀:避免髒讀和不可重複讀。虛幻讀可能發生。

4、序列化:避免以上所有的讀問題。

事務的隔離級別越高,效能會降的越低。其實就是犧牲效能來提高準確性。在實際中,一般選取中間的隔離級別。

mysql預設隔離級別:可重複讀。

oracle預設隔離級別:已提交讀。

五、spring封裝事務

首先spring封裝了我們需要進行的事務操作。事務操作是什麼呢。比如說我們首先需要開啟事務,進行操作後,提交事務。如果發生錯誤,回滾事務,如果中途未發生錯誤,則事務進行提交。如果spring沒有對事務進行封裝,我們需要沒進行一次操作都重新寫事務的處理程式碼。spring封裝後,事務程式碼被封裝,我們不用一遍遍的重複編寫程式碼,配置好後,不用書寫事務程式碼。接下來我們瞭解幾個spring中事務的相關概念。

1、PlatformTransactionManager平臺事務管理器

在不同的平臺,操作程式碼的事務各不相同,spring為我們提供了一個介面。這個介面就是PlatformTransactionManager。

我們可以看一下里面的原始碼。提供了一個獲得事務的方法,一個提交事務的方法以及一個回滾事務的方法。此處貼一下原始碼

/*
 * Copyright 2002-2012 the original author or authors.
 *
 * Licensed 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.springframework.transaction;

/**
 * This is the central interface in Spring's transaction infrastructure.
 * Applications can use this directly, but it is not primarily meant as API:
 * Typically, applications will work with either TransactionTemplate or
 * declarative transaction demarcation through AOP.
 *
 * <p>For implementors, it is recommended to derive from the provided
 * {@link org.springframework.transaction.support.AbstractPlatformTransactionManager}
 * class, which pre-implements the defined propagation behavior and takes care
 * of transaction synchronization handling. Subclasses have to implement
 * template methods for specific states of the underlying transaction,
 * for example: begin, suspend, resume, commit.
 *
 * <p>The default implementations of this strategy interface are
 * {@link org.springframework.transaction.jta.JtaTransactionManager} and
 * {@link org.springframework.jdbc.datasource.DataSourceTransactionManager},
 * which can serve as an implementation guide for other transaction strategies.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @since 16.05.2003
 * @see org.springframework.transaction.support.TransactionTemplate
 * @see org.springframework.transaction.interceptor.TransactionInterceptor
 * @see org.springframework.transaction.interceptor.TransactionProxyFactoryBean
 */
public interface PlatformTransactionManager {

    /**
     * Return a currently active transaction or create a new one, according to
     * the specified propagation behavior.
     * <p>Note that parameters like isolation level or timeout will only be applied
     * to new transactions, and thus be ignored when participating in active ones.
     * <p>Furthermore, not all transaction definition settings will be supported
     * by every transaction manager: A proper transaction manager implementation
     * should throw an exception when unsupported settings are encountered.
     * <p>An exception to the above rule is the read-only flag, which should be
     * ignored if no explicit read-only mode is supported. Essentially, the
     * read-only flag is just a hint for potential optimization.
     * @param definition TransactionDefinition instance (can be {@code null} for defaults),
     * describing propagation behavior, isolation level, timeout etc.
     * @return transaction status object representing the new or current transaction
     * @throws TransactionException in case of lookup, creation, or system errors
     * @throws IllegalTransactionStateException if the given transaction definition
     * cannot be executed (for example, if a currently active transaction is in
     * conflict with the specified propagation behavior)
     * @see TransactionDefinition#getPropagationBehavior
     * @see TransactionDefinition#getIsolationLevel
     * @see TransactionDefinition#getTimeout
     * @see TransactionDefinition#isReadOnly
     */
    TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;

    /**
     * Commit the given transaction, with regard to its status. If the transaction
     * has been marked rollback-only programmatically, perform a rollback.
     * <p>If the transaction wasn't a new one, omit the commit for proper
     * participation in the surrounding transaction. If a previous transaction
     * has been suspended to be able to create a new one, resume the previous
     * transaction after committing the new one.
     * <p>Note that when the commit call completes, no matter if normally or
     * throwing an exception, the transaction must be fully completed and
     * cleaned up. No rollback call should be expected in such a case.
     * <p>If this method throws an exception other than a TransactionException,
     * then some before-commit error caused the commit attempt to fail. For
     * example, an O/R Mapping tool might have tried to flush changes to the
     * database right before commit, with the resulting DataAccessException
     * causing the transaction to fail. The original exception will be
     * propagated to the caller of this commit method in such a case.
     * @param status object returned by the {@code getTransaction} method
     * @throws UnexpectedRollbackException in case of an unexpected rollback
     * that the transaction coordinator initiated
     * @throws HeuristicCompletionException in case of a transaction failure
     * caused by a heuristic decision on the side of the transaction coordinator
     * @throws TransactionSystemException in case of commit or system errors
     * (typically caused by fundamental resource failures)
     * @throws IllegalTransactionStateException if the given transaction
     * is already completed (that is, committed or rolled back)
     * @see TransactionStatus#setRollbackOnly
     */
    void commit(TransactionStatus status) throws TransactionException;

    /**
     * Perform a rollback of the given transaction.
     * <p>If the transaction wasn't a new one, just set it rollback-only for proper
     * participation in the surrounding transaction. If a previous transaction
     * has been suspended to be able to create a new one, resume the previous
     * transaction after rolling back the new one.
     * <p><b>Do not call rollback on a transaction if commit threw an exception.</b>
     * The transaction will already have been completed and cleaned up when commit
     * returns, even in case of a commit exception. Consequently, a rollback call
     * after commit failure will lead to an IllegalTransactionStateException.
     * @param status object returned by the {@code getTransaction} method
     * @throws TransactionSystemException in case of rollback or system errors
     * (typically caused by fundamental resource failures)
     * @throws IllegalTransactionStateException if the given transaction
     * is already completed (that is, committed or rolled back)
     */
    void rollback(TransactionStatus status) throws TransactionException;

}

我們通過檢視介面發現AbstractPlatformTransactionManager實現了這一介面。其中提供了一些方法。繼續檢視誰繼承了該抽象類。

發現有兩個:DataSourceTransactionManager與HibernateTransitionmanager。

DataSourceTransactionManager:這一事務管理類,在用spring的jdbc以及mybaties進行操作事務的時候使用。

HibernateTransitionmanager:在用hiberante進行操作事務的時候使用。

2、TransactionDefinition事務定義資訊

主要記錄了事務的定義資訊相關。

記錄了事務的隔離級別,事務傳播行為,超時資訊,只讀資訊的基本資訊。此處可以看一下原始碼感受一下,這裡面的一些資訊,後面會講解

/*
 * Copyright 2002-2015 the original author or authors.
 *
 * Licensed 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.springframework.transaction;

import java.sql.Connection;

/**
 * Interface that defines Spring-compliant transaction properties.
 * Based on the propagation behavior definitions analogous to EJB CMT attributes.
 *
 * <p>Note that isolation level and timeout settings will not get applied unless
 * an actual new transaction gets started. As only {@link #PROPAGATION_REQUIRED},
 * {@link #PROPAGATION_REQUIRES_NEW} and {@link #PROPAGATION_NESTED} can cause
 * that, it usually doesn't make sense to specify those settings in other cases.
 * Furthermore, be aware that not all transaction managers will support those
 * advanced features and thus might throw corresponding exceptions when given
 * non-default values.
 *
 * <p>The {@link #isReadOnly() read-only flag} applies to any transaction context,
 * whether backed by an actual resource transaction or operating non-transactionally
 * at the resource level. In the latter case, the flag will only apply to managed
 * resources within the application, such as a Hibernate {@code Session}.
 *
 * @author Juergen Hoeller
 * @since 08.05.2003
 * @see PlatformTransactionManager#getTransaction(TransactionDefinition)
 * @see org.springframework.transaction.support.DefaultTransactionDefinition
 * @see org.springframework.transaction.interceptor.TransactionAttribute
 */
public interface TransactionDefinition {

    /**
     * Support a current transaction; create a new one if none exists.
     * Analogous to the EJB transaction attribute of the same name.
     * <p>This is typically the default setting of a transaction definition,
     * and typically defines a transaction synchronization scope.
     */
    int PROPAGATION_REQUIRED = 0;

    /**
     * Support a current transaction; execute non-transactionally if none exists.
     * Analogous to the EJB transaction attribute of the same name.
     * <p><b>NOTE:</b> For transaction managers with transaction synchronization,
     * {@code PROPAGATION_SUPPORTS} is slightly different from no transaction
     * at all, as it defines a transaction scope that synchronization might apply to.
     * As a consequence, the same resources (a JDBC {@code Connection}, a
     * Hibernate {@code Session}, etc) will be shared for the entire specified
     * scope. Note that the exact behavior depends on the actual synchronization
     * configuration of the transaction manager!
     * <p>In general, use {@code PROPAGATION_SUPPORTS} with care! In particular, do
     * not rely on {@code PROPAGATION_REQUIRED} or {@code PROPAGATION_REQUIRES_NEW}
     * <i>within</i> a {@code PROPAGATION_SUPPORTS} scope (which may lead to
     * synchronization conflicts at runtime). If such nesting is unavoidable, make sure
     * to configure your transaction manager appropriately (typically switching to
     * "synchronization on actual transaction").
     * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization
     * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#SYNCHRONIZATION_ON_ACTUAL_TRANSACTION
     */
    int PROPAGATION_SUPPORTS = 1;

    /**
     * Support a current transaction; throw an exception if no current transaction
     * exists. Analogous to the EJB transaction attribute of the same name.
     * <p>Note that transaction synchronization within a {@code PROPAGATION_MANDATORY}
     * scope will always be driven by the surrounding transaction.
     */
    int PROPAGATION_MANDATORY = 2;

    /**
     * Create a new transaction, suspending the current transaction if one exists.
     * Analogous to the EJB transaction attribute of the same name.
     * <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
     * on all transaction managers. This in particular applies to
     * {@link org.springframework.transaction.jta.JtaTransactionManager},
     * which requires the {@code javax.transaction.TransactionManager} to be
     * made available it to it (which is server-specific in standard Java EE).
     * <p>A {@code PROPAGATION_REQUIRES_NEW} scope always defines its own
     * transaction synchronizations. Existing synchronizations will be suspended
     * and resumed appropriately.
     * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
     */
    int PROPAGATION_REQUIRES_NEW = 3;

    /**
     * Do not support a current transaction; rather always execute non-transactionally.
     * Analogous to the EJB transaction attribute of the same name.
     * <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
     * on all transaction managers. This in particular applies to
     * {@link org.springframework.transaction.jta.JtaTransactionManager},
     * which requires the {@code javax.transaction.TransactionManager} to be
     * made available it to it (which is server-specific in standard Java EE).
     * <p>Note that transaction synchronization is <i>not</i> available within a
     * {@code PROPAGATION_NOT_SUPPORTED} scope. Existing synchronizations
     * will be suspended and resumed appropriately.
     * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
     */
    int PROPAGATION_NOT_SUPPORTED = 4;

    /**
     * Do not support a current transaction; throw an exception if a current transaction
     * exists. Analogous to the EJB transaction attribute of the same name.
     * <p>Note that transaction synchronization is <i>not</i> available within a
     * {@code PROPAGATION_NEVER} scope.
     */
    int PROPAGATION_NEVER = 5;

    /**
     * Execute within a nested transaction if a current transaction exists,
     * behave like {@link #PROPAGATION_REQUIRED} else. There is no analogous
     * feature in EJB.
     * <p><b>NOTE:</b> Actual creation of a nested transaction will only work on
     * specific transaction managers. Out of the box, this only applies to the JDBC
     * {@link org.springframework.jdbc.datasource.DataSourceTransactionManager}
     * when working on a JDBC 3.0 driver. Some JTA providers might support
     * nested transactions as well.
     * @see org.springframework.jdbc.datasource.DataSourceTransactionManager
     */
    int PROPAGATION_NESTED = 6;


    /**
     * Use the default isolation level of the underlying datastore.
     * All other levels correspond to the JDBC isolation levels.
     * @see java.sql.Connection
     */
    int ISOLATION_DEFAULT = -1;

    /**
     * Indicates that dirty reads, non-repeatable reads and phantom reads
     * can occur.
     * <p>This level allows a row changed by one transaction to be read by another
     * transaction before any changes in that row have been committed (a "dirty read").
     * If any of the changes are rolled back, the second transaction will have
     * retrieved an invalid row.
     * @see java.sql.Connection#TRANSACTION_READ_UNCOMMITTED
     */
    int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;

    /**
     * Indicates that dirty reads are prevented; non-repeatable reads and
     * phantom reads can occur.
     * <p>This level only prohibits a transaction from reading a row
     * with uncommitted changes in it.
     * @see java.sql.Connection#TRANSACTION_READ_COMMITTED
     */
    int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;

    /**
     * Indicates that dirty reads and non-repeatable reads are prevented;
     * phantom reads can occur.
     * <p>This level prohibits a transaction from reading a row with uncommitted changes
     * in it, and it also prohibits the situation where one transaction reads a row,
     * a second transaction alters the row, and the first transaction re-reads the row,
     * getting different values the second time (a "non-repeatable read").
     * @see java.sql.Connection#TRANSACTION_REPEATABLE_READ
     */
    int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;

    /**
     * Indicates that dirty reads, non-repeatable reads and phantom reads
     * are prevented.
     * <p>This level includes the prohibitions in {@link #ISOLATION_REPEATABLE_READ}
     * and further prohibits the situation where one transaction reads all rows that
     * satisfy a {@code WHERE} condition, a second transaction inserts a row
     * that satisfies that {@code WHERE} condition, and the first transaction
     * re-reads for the same condition, retrieving the additional "phantom" row
     * in the second read.
     * @see java.sql.Connection#TRANSACTION_SERIALIZABLE
     */
    int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;


    /**
     * Use the default timeout of the underlying transaction system,
     * or none if timeouts are not supported.
     */
    int TIMEOUT_DEFAULT = -1;


    /**
     * Return the propagation behavior.
     * <p>Must return one of the {@code PROPAGATION_XXX} constants
     * defined on {@link TransactionDefinition this interface}.
     * @return the propagation behavior
     * @see #PROPAGATION_REQUIRED
     * @see org.springframework.transaction.support.TransactionSynchronizationManager#isActualTransactionActive()
     */
    int getPropagationBehavior();

    /**
     * Return the isolation level.
     * <p>Must return one of the {@code ISOLATION_XXX} constants
     * defined on {@link TransactionDefinition this interface}.
     * <p>Only makes sense in combination with {@link #PROPAGATION_REQUIRED}
     * or {@link #PROPAGATION_REQUIRES_NEW}.
     * <p>Note that a transaction manager that does not support custom isolation levels
     * will throw an exception when given any other level than {@link #ISOLATION_DEFAULT}.
     * @return the isolation level
     */
    int getIsolationLevel();

    /**
     * Return the transaction timeout.
     * <p>Must return a number of seconds, or {@link #TIMEOUT_DEFAULT}.
     * <p>Only makes sense in combination with {@link #PROPAGATION_REQUIRED}
     * or {@link #PROPAGATION_REQUIRES_NEW}.
     * <p>Note that a transaction manager that does not support timeouts will throw
     * an exception when given any other timeout than {@link #TIMEOUT_DEFAULT}.
     * @return the transaction timeout
     */
    int getTimeout();

    /**
     * Return whether to optimize as a read-only transaction.
     * <p>The read-only flag applies to any transaction context, whether
     * backed by an actual resource transaction
     * ({@link #PROPAGATION_REQUIRED}/{@link #PROPAGATION_REQUIRES_NEW}) or
     * operating non-transactionally at the resource level
     * ({@link #PROPAGATION_SUPPORTS}). In the latter case, the flag will
     * only apply to managed resources within the application, such as a
     * Hibernate {@code Session}.
     <<     * <p>This just serves as a hint for the actual transaction subsystem;
     * it will <i>not necessarily</i> cause failure of write access attempts.
     * A transaction manager which cannot interpret the read-only hint will
     * <i>not</i> throw an exception when asked for a read-only transaction.
     * @return {@code true} if the transaction is to be optimized as read-only
     * @see org.springframework.transaction.support.TransactionSynchronization#beforeCommit(boolean)
     * @see org.springframework.transaction.support.TransactionSynchronizationManager#isCurrentTransactionReadOnly()
     */
    boolean isReadOnly();

    /**
     * Return the name of this transaction. Can be {@code null}.
     * <p>This will be used as the transaction name to be shown in a
     * transaction monitor, if applicable (for example, WebLogic's).
     * <p>In case of Spring's declarative transactions, the exposed name will be
     * the {@code fully-qualified class name + "." + method name} (by default).
     * @return the name of this transaction
     * @see org.springframework.transaction.interceptor.TransactionAspectSupport
     * @see org.springframework.transaction.support.TransactionSynchronizationManager#getCurrentTransactionName()
     */
    String getName();

}

3、TransactionStatus事務狀態資訊

記錄事務的狀態資訊,可以看看原始碼。理解一下大神的思想。

/*
 * Copyright 2002-2013 the original author or authors.
 *
 * Licensed 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.springframework.transaction;

import java.io.Flushable;

/**
 * Representation of the status of a transaction.
 *
 * <p>Transactional code can use this to retrieve status information,
 * and to programmatically request a rollback (instead of throwing
 * an exception that causes an implicit rollback).
 *
 * <p>Derives from the SavepointManager interface to provide access
 * to savepoint management facilities. Note that savepoint management
 * is only available if supported by the underlying transaction manager.
 *
 * @author Juergen Hoeller
 * @since 27.03.2003
 * @see #setRollbackOnly()
 * @see PlatformTransactionManager#getTransaction
 * @see org.springframework.transaction.support.TransactionCallback#doInTransaction
 * @see org.springframework.transaction.interceptor.TransactionInterceptor#currentTransactionStatus()
 */
public interface TransactionStatus extends SavepointManager, Flushable {

    /**
     * Return whether the present transaction is new (else participating
     * in an existing transaction, or potentially not running in an
     * actual transaction in the first place).
     */
    boolean isNewTransaction();

    /**
     * Return whether this transaction internally carries a savepoint,
     * that is, has been created as nested transaction based on a savepoint.
     * <p>This method is mainly here for diagnostic purposes, alongside
     * {@link #isNewTransaction()}. For programmatic handling of custom
     * savepoints, use SavepointManager's operations.
     * @see #isNewTransaction()
     * @see #createSavepoint
     * @see #rollbackToSavepoint(Object)
     * @see #releaseSavepoint(Object)
     */
    boolean hasSavepoint();

    /**
     * Set the transaction rollback-only. This instructs the transaction manager
     * that the only possible outcome of the transaction may be a rollback, as
     * alternative to throwing an exception which would in turn trigger a rollback.
     * <p>This is mainly intended for transactions managed by
     * {@link org.springframework.transaction.support.TransactionTemplate} or
     * {@link org.springframework.transaction.interceptor.TransactionInterceptor},
     * where the actual commit/rollback decision is made by the container.
     * @see org.springframework.transaction.support.TransactionCallback#doInTransaction
     * @see org.springframework.transaction.interceptor.TransactionAttribute#rollbackOn
     */
    void setRollbackOnly();

    /**
     * Return whether the transaction has been marked as rollback-only
     * (either by the application or by the transaction infrastructure).
     */
    boolean isRollbackOnly();

    /**
     * Flush the underlying session to the datastore, if applicable:
     * for example, all affected Hibernate/JPA sessions.
     */
    @Override
    void flush();

    /**
     * Return whether this transaction is completed, that is,
     * whether it has already been committed or rolled back.
     * @see PlatformTransactionManager#commit
     * @see PlatformTransactionManager#rollback
     */
    boolean isCompleted();

}

4、事務的傳播行為

一般來說我們都是一個業務層進行業務操作,如果涉及到一個業務層需要呼叫另一個業務層。這時就需要涉及到事務的傳播行為用來規定在兩個多個業務層中如何進行事務的管理。

(1)PROPAGATION_REQUIRED:支援當前事務,如果不存在,則新建一個(預設)。

(2)PROPAGATION_SUPPORTS:支援當前事務,如果不存在,則不使用事務。

(3)PROPAGATION_MANDATORY:支援當前事務,如果不存在,則丟擲異常。

(4)PROPAGATION_REQUIRES_NEW:如果當前事務不存在,則新建一個事務。如果當前事務存在,掛起這個事務再新建一個事務。

(5)PROPAGATION_NOT_SUPPORTED:不支援當前事務,以不使用事務的方式執行,如果當前存在事務,則掛起事務。

(6)PROPAGATION_NEVER:以非事務的方式執行,如果存在事務,丟擲異常。

(7)PROPAGATION_NESTED:如果當前事務存在,則巢狀事務來執行。

六、spring的事務三種實現方式

三種方式分別為編碼式,xml配置方式,註解配置方式。編碼式瞭解即可,實際開發都是後兩種。

1、編碼式

(1)在spring容器中配置核心事務管理器,依賴於連線池,連線池的配置方式可參考之前的文章。

<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
    <property name="dataSource" ref="dataSource" ></property>
</bean>

(2)在spring容器中配置事務模板物件

<bean name="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate" >
    <property name="transactionManager" ref="transactionManager" ></property>
</bean>

(3)在業務層中配置事務模板物件

<bean name="accountDao" class="com.jichi.dao.AccountDaoImpl" >
    <property name="dataSource" ref="dataSource" ></property>
</bean>
<bean name="accountService" class="com.jichi.service.AccountServiceImpl" >
    <property name="ad" ref="accountDao" ></property>
    <property name="tt" ref="transactionTemplate" ></property>
</bean>  

(4)編寫事務實現程式碼,在需要事務的方法中,用模板物件呼叫excute方法,實現其中的介面。重寫介面中的方法,講需要進行事務管理的程式碼放入其中。

public class AccountServiceImpl implements AccountService {

    private AccountDao ad ;
    private TransactionTemplate tt;
@Override
public void transfer(final Integer from,final Integer to,final Double money) { tt.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus arg0) { //減錢 ad.decreaseMoney(from, money); //加錢 ad.increaseMoney(to, money); } }); } }

2、xml方式

(1)導包

aopaliance,springaop,aspectJ,springaspectss

(2)配置事務管理器

<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
    <property name="dataSource" ref="dataSource" ></property>
</bean>

(3)配置事務的通知,根據方法名進行匹配。

<tx:advice id="txAdvice" transaction-manager="transactionManager" >
    <tx:attributes>
        <!-- 以方法為單位,指定方法應用什麼事務屬性
            isolation:隔離級別
            propagation:傳播行為
            read-only:是否只讀
       timeout:過期時間
        rollback-for
        no-rollback-for
--> <tx:method name="save*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" /> <tx:method name="persist*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" /> <tx:method name="update*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" /> <tx:method name="modify*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" /> <tx:method name="delete*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" /> <tx:method name="remove*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" /> <tx:method name="get*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true" /> <tx:method name="find*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true" /> <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" /> </tx:attributes> </tx:advice>

(4)配置織入。首先配置切點。表示對哪些方法要進行增強。配置切面。pointcut-ref切點的名稱,advice-ref通知的名稱。

<aop:config  >
    <aop:pointcut expression="execution(* com.jichi.service.*ServiceImpl.*(..))" id="txPc"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPc" />
</aop:config>

3、註解方式

(1)配置事務管理器

<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
    <property name="dataSource" ref="dataSource" ></property>
</bean>

(2)開啟事務管理的註解

<tx:annotation-driven/>

(3)在使用事務的類上添加註解,在需要事務的方法上,打上註解,在註解中配置事務隔離級別,事務傳播等資訊。預設對該類中所有的方法,執行類上的配置,如果在某個方法上進行配置,則執行方法上的配置。

@Transactional(isolation=Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED,readOnly=true)
public class AccountServiceImpl implements AccountService {

    private AccountDao ad ;
    private TransactionTemplate tt;
    
    @Override
    @Transactional(isolation=Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED,readOnly=false)
    public void transfer(final Integer from,final Integer to,final Double money) {
                //減錢
                ad.decreaseMoney(from, money);
                int i = 1/0;
                //加錢
                ad.increaseMoney(to, money);
    }
}