什麼是事務?
通俗理解,事務其實就是一系列指令的集合。
為什麼要使用事務管理?
我們在實際業務場景中,經常會遇到資料頻繁修改讀取的問題。在同一時刻,不同的業務邏輯對同一個表資料進行修改,這種衝突很可能造成資料不可挽回的錯亂,所以我們需要用事務來對資料進行管理。
事務的四個特性:
- 原子性
原子性:操作這些指令時,要麼全部執行成功,要麼全部不執行。只要其中一個指令執行失敗,所有的指令都執行失敗,資料進行回滾,回到執行指令前的資料狀態。 - 一致性
事務的執行使資料從一個狀態轉換為另一個狀態,但是對於整個資料的完整性保持穩定。 - 隔離性
在該事務執行的過程中,無論發生的任何資料的改變都應該只存在於該事務之中,對外界不存在任何影響。只有在事務確定正確提交之後,才會顯示該事務對資料的改變。其他事務才能獲取到這些改變後的資料。 - 永續性
當事務正確完成後,它對於資料的改變是永久性的。
Spring中的事務管理分類:
- 程式設計式事務管理機制
- 宣告式事務管理機制
下面就銀行轉賬這一例項來講解如何利用這兩種由Spring提供的事務處理機制來進行相應的事務處理。
專案前準備工作:
- 在專案中匯入相應的jar包
-
編寫專案相應的介面和介面實現類,本專案有兩個介面–【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