基於Spring中的事務管理機制

james發表於2017-12-21

什麼是事務?

通俗理解,事務其實就是一系列指令的集合。

為什麼要使用事務管理?

我們在實際業務場景中,經常會遇到資料頻繁修改讀取的問題。在同一時刻,不同的業務邏輯對同一個表資料進行修改,這種衝突很可能造成資料不可挽回的錯亂,所以我們需要用事務來對資料進行管理。

事務的四個特性:

  1. 原子性
    原子性:操作這些指令時,要麼全部執行成功,要麼全部不執行。只要其中一個指令執行失敗,所有的指令都執行失敗,資料進行回滾,回到執行指令前的資料狀態。
  2. 一致性
    事務的執行使資料從一個狀態轉換為另一個狀態,但是對於整個資料的完整性保持穩定。
  3. 隔離性
    在該事務執行的過程中,無論發生的任何資料的改變都應該只存在於該事務之中,對外界不存在任何影響。只有在事務確定正確提交之後,才會顯示該事務對資料的改變。其他事務才能獲取到這些改變後的資料。
  4. 永續性
    當事務正確完成後,它對於資料的改變是永久性的。

Spring中的事務管理分類:

  1. 程式設計式事務管理機制
  2. 宣告式事務管理機制

下面就銀行轉賬這一例項來講解如何利用這兩種由Spring提供的事務處理機制來進行相應的事務處理。

專案前準備工作:

  1. 在專案中匯入相應的jar包
  2. 編寫專案相應的介面和介面實現類,本專案有兩個介面–【AccountService,AccountDAO】,兩個介面實現類–【AccountServiceImpl,AccountDAOImpl】,具體程式碼如下:

                   **AccountService介面**

    package cn.muke.spring.demo1;
    /**

    * @author 熊濤
 *銀行轉賬的業務層介面
 */
public interface AccountService {

    /*
     * @param out:轉出賬戶
     * @param in:轉入賬戶
     * @param money:轉賬金額
     */
    public void transfer(String out,String in,Double money);
    
}


            **AccountService介面實現類AccountServiceImpl**
package cn.muke.spring.demo1;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
public class AccountServiceImpl implements AccountService {    
    //注入轉賬的DAO
    private AccountDAO accountDao;    
    //注入事務管理的模板
    private TransactionTemplate transactionTemplate;

    /**
     * @param out    :轉出賬號
     * @param in    :轉入賬號
     * @param money    :轉賬金額
     */
    @Override
    public void transfer(final String out, final String in, final Double money) {
            
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {

            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                accountDao.outMoney(out, money);
                int i = 1/0;
                accountDao.inMoney(in, money);
            }
        });
    }

    public void setAccountDao(AccountDAO accountDao) {
        this.accountDao = accountDao;
    }

    public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }

}
           
           **AccountDAO介面**


package cn.muke.spring.demo1;
/**
 * @author 熊濤
 *轉賬案例DAO層的介面
 */
public interface AccountDAO {

    /*
     * @param out:轉出賬號
     * @param money:轉賬金額
     */
    public void outMoney(String out,Double money);
    /*
     * @param in:轉入賬戶
     * @param money:轉賬金額
     */
    public void inMoney(String in,Double money);
}


                    **AccountDAO介面的實現類AccountDAOImpl**

package cn.muke.spring.demo1;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
/**

  • @author 熊濤

*轉賬案例DAO層的實現類
*/
public class AccountDAOImpl extends JdbcDaoSupport implements AccountDAO {

/*
 * @param out:轉出賬號
 * @param money:轉賬金額
 */
@Override
public void outMoney(String out, Double money) {
    
    String sql = "update account set money = money - ? where name = ? ";
    this.getJdbcTemplate().update(sql, money,out);
}

/*
 * @param in:轉入賬戶
 * @param money:轉賬金額
 */
@Override
public void inMoney(String in, Double money) {
    
    String sql = "update account set money = money + ? where name = ? ";
    this.getJdbcTemplate().update(sql, money,in);
}

}

程式設計式事務管理機制

package cn.muke.spring.demo1;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
public class AccountServiceImpl implements AccountService {    
    //注入轉賬的DAO
    private AccountDAO accountDao;    
    //注入事務管理的模板
    private TransactionTemplate transactionTemplate;

    /**
     * @param out    :轉出賬號
     * @param in    :轉入賬號
     * @param money    :轉賬金額
     */
    @Override
    public void transfer(final String out, final String in, final Double money) {            
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                accountDao.outMoney(out, money);
                int i = 1/0;
                accountDao.inMoney(in, money);
            }
        });
    }
    public void setAccountDao(AccountDAO accountDao) {
        this.accountDao = accountDao;
    }
    public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }
}

解釋:主要是通過transaction提供的模板來進行事務的處理。

使用宣告式的方法進行事務處理

【1】基於TransactionProxyFactoryBean的事務處理機制

要點:(1)主要是在Spring的配置檔案中配置業務層的代理,程式碼例如:
<!– 配置業務層的代理 –>

<bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
            <!-- 配置目標物件 -->
            <property name="target" ref="accountService"/>
            <!-- 注入事務管理器 -->
            <property name="transactionManager" ref="transactionManager"/>
            <!-- 注入事務的屬性 -->
        <property name="transactionAttributes">
            <props>
                <!-- 
                    prop的格式:
                        * PROPAGATION    :事務的傳播行為
                        * ISOTATION        :事務的隔離級別
                        * readOnly        :只讀
                        * -EXCEPTION    :發生哪些異常回滾事務
                        * +EXCEPTION     :發生哪些異常不回滾事務
                 -->
                <prop key="transfer">PROPAGATION_REQUIRED</prop>
                <!-- <prop key="transfer">PROPAGATION_REQUIRED,readOnly</prop> -->
                <!-- <prop key="transfer">PROPAGATION_REQUIRED,+java.lang.ArithmeticException</prop> -->
            </props>
        </property>
    </bean>

(2)在使用業務層時需注入業務層的代理

 @Resource(name="accountServiceProxy")
 
 

【2】基於AspectJ的XML方式

此種方式是利用了Spring AOP這一特性完成事務管理機制。其要點是配置事務通知和切面和切點,而且此種代理為自動代理。其在Spring配置檔案的配置如下:
 <!-- 配置事務的通知 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="transfer" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    
    <!-- 配置切面 -->
    <aop:config>
        <!-- 配置切入點 -->
        <aop:pointcut expression="execution(* cn.muke.spring.demo3.AccountService+.*(..))" id="pointcut1"/>
        <!-- 配置切面 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
    </aop:config>

【3】基於註解的事務管理機制

其要點是在Spring配置檔案完成事務的開啟,另外還需在需要進行事務管理的業務層類出標記上事務的關鍵字,@Tansactional       

最後附上對於該專案的原始碼,原始碼中有一個名為database的檔案改檔案有關於建立資料庫的sql語句,另外原始碼中海油對於每一種事務管理機制的測試類。
連結:https://pan.baidu.com/s/1hspMvnY 密碼:g2h7

相關文章