大家可以關註作者的賬號,關註從零開始學Spring筆記文集。也可以根據目錄前往作者的博客園博客進行學習。本片文件將基於黑馬程式員就業班視頻進行學習以及資料的分享,並記錄筆記和自己的看法。歡迎大家一起學習和討論。 "【從零開始學Spring筆記】Spring學習路線" 什麼事務 事務:邏輯上的一組操作 ...
大家可以關註作者的賬號,關註從零開始學Spring筆記文集。也可以根據目錄前往作者的博客園博客進行學習。本片文件將基於黑馬程式員就業班視頻進行學習以及資料的分享,並記錄筆記和自己的看法。歡迎大家一起學習和討論。
【從零開始學Spring筆記】Spring學習路線
什麼事務
事務:邏輯上的一組操作,組成這組操作的各個單元,要麼全都成功,要麼全都失敗。
事務的特性
原子性:事務不可分割
一致性:事務執行前後數據完整性保持一致
隔離性:一個事務的執行不應該受到其他事務的干擾
持久性:一旦事務結束,數據就持久化到資料庫
如果不考慮隔離性引發安全性問題
- 讀問題
臟讀 :一個事務讀到另一個事務未提交的數據
不可重覆讀 :一個事務讀到另一個事務已經提交的update的數據,導致一個事務中多次查詢結果不一致
虛讀、幻讀 :一個事務讀到另一個事務已經提交的insert的數據,導致一個事務中多次查詢結果不一致。 - 寫問題
丟失更新
解決讀問題
設置事務的隔離級別
- Read uncommitted :未提交讀,任何讀問題解決不了。(效率最高,但是安全性最低)
Read committed :已提交讀,解決臟讀,但是不可重覆讀和虛讀有可能發生。
Repeatable read :重覆讀,解決臟讀和不可重覆讀,但是虛讀有可能發生。
Serializable :解決所有讀問題。
Spring的事務管理的API
PlatformTransactionManager:平臺事務管理器
平臺事務管理器:介面,是Spring用於管理事務的真正的對象。
- DataSourceTransactionManager :底層使用JDBC管理事務
HibernateTransactionManager :底層使用Hibernate管理事務
TransactionDefinition :事務定義信息
事務定義:用於定義事務的相關的信息,隔離級別、超時信息、傳播行為、是否只讀
TransactionStatus:事務的狀態
事務狀態:用於記錄在事務管理過程中,事務的狀態的對象。
事務管理的API的關係:
Spring進行事務管理的時候,首先平臺事務管理器根據事務定義信息進行事務的管理,在事務管理過程中,產生各種狀態,將這些狀態的信息記錄到事務狀態的對象中。
Spring的傳播行為
在實際開發中,可能會遇到特別複雜的業務邏輯層,裡面事務繁多,還可能會相互調用。這時候就需要事務的傳播行為來進行管理。
Spring中提供了七種事務的傳播行為:
保證多個操作在同一個事務中
$\color{red}{**}$PROPAGATION_REQUIRED :預設值,如果A中有事務,使用A中的事務,將操作包含進來。如果A沒有,創建一個新的事務,將操作包含進來
PROPAGATION_SUPPORTS :支持事務,如果A中有事務,使用A中的事務。如果A沒有事務,不使用事務。
PROPAGATION_MANDATORY :如果A中有事務,使用A中的事務。如果A沒有事務,拋出異常。
保證多個操作不在同一個事務中
$\color{red}{**}$PROPAGATION_REQUIRES_NEW :如果A中有事務,將A的事務掛起(暫停),創建新事務,只包含自身操作。如果A中沒有事務,創建一個新事務,包含自身操作。
PROPAGATION_NOT_SUPPORTED :如果A中有事務,將A的事務掛起。不使用事務管理。
PROPAGATION_NEVER :如果A中有事務,報異常。
嵌套式事務
$\color{red}{**}$PROPAGATION_NESTED :嵌套事務,如果A中有事務,按照A的事務執行,執行完成後,設置一個保存點,執行B中的操作,如果沒有異常,執行通過,如果有異常,可以選擇回滾到最初始位置,也可以回滾到保存點。
搭建Spring的事務管理的環境
第一步:創建 Senvice的介面和實現類
package com.tyust.tx.demo1;
public interface AccountService {
public void transfer(String form, String to ,Double money);
}
package com.tyust.tx.demo1;
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
@Override
/**
* from:傳出賬戶
* to:轉入賬戶
* money:金額
*/
public void transfer(String form, String to, Double money) {
accountDao.outMoney(form, money);
accountDao.inMoney(to, money);
}
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
}
第二步:創建 DAO的介面和實現類
package com.tyust.tx.demo1;
import org.springframework.jdbc.core.JdbcTemplate;
public interface AccountDao {
public void outMoney(String from, double money);
public void inMoney(String to, double money);
}
package com.tyust.tx.demo1;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
@Override
public void outMoney(String from, double money) {
this.getJdbcTemplate().update("update account set money = money - ? where name = ?", money, from);
}
@Override
public void inMoney(String to, double money) {
this.getJdbcTemplate().update("update account set money = money + ? where name = ?", money, to);
}
}
第三步:配置Senvice和DAO: 交給Spring管理
<bean id = "accountDao" class="com.tyust.tx.demo1.AccountDaoImpl">
<property name="dataSource" ref="ds"></property>
</bean>
<bean id = "accountService" class="com.tyust.tx.demo1.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
第四步:配置連接池和JDBC的模板
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置C3p0連接池 -->
<bean id="ds" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"></property>
</bean>
第五步:測試
package com.tyust.tx.demo1;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:tx.xml")
public class SpringDemo {
@Resource(name = "accountService")
private AccountService accountService;
@Test
public void demo() {
accountService.transfer("關羽", "張飛", 1000d);
}
}
輸出結果
為什麼引入事務
上例就是沒有事務的實現方法,如果在transfer()方法中轉出和轉入之間存在異常,就會出現轉出實現了,轉入卻沒有實現,這在現實生活中是不允許的。所以需要事務的保障
Spring的事務管理——編程式事務(需要手動編寫代碼)
第一步:配置平臺事務管理器
<!-- 配置事務平臺管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
第二步:Spring 提供了事務管理的模板類
<bean id="transactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"></property>
</bean>
第三步:在業務層註入事務管理的模板
//註入事務管理的模板
private TransactionTemplate transactionTemplate;
</bean>
<bean id="accountService"
class="com.tyust.tx.demo1.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
<property name="transactionTemplate"
ref="transactionTemplate"></property>
</bean>
第四步:編寫事務管理的代碼
public void transfer(final String form,final String to, final Double money) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
accountDao.outMoney(form, money);
int i =1/0;
accountDao.inMoney(to, money);
}
});
}
第五步:測試
發現並沒有出現轉出實現了,轉入卻沒有實現的情況
Spring的事務管理——聲明式事務管理(通過配置實現)---AOP
XML方式的聲明式事務管理
第一步:引入aop的開發包
第二步:恢復轉賬環境
把上一個例子添加的編輯事務代碼全部刪除
第三步:配置事務管理器
<bean id ="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
第四步:配置增強
<!-- 配置事務的增強 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
事務管理規範
<tx:method name="save" propagation="REQUIRED" isolation="DEFAULT"/>
<tx:method name="update" propagation="REQUIRED" />
<tx:method name="delete" propagation="REQUIRED" />
<tx:method name="find" read-only="true"/>
read-only:只讀,不能增刪改,只能查
timeout:-1 ->一直有效
第五步:AOP的配置
<aop:config>
<aop:pointcut expression="execution(* com.tyust.tx.demo2.AccountServiceImpl.*(..) )" id="pointcut1"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
</aop:config>
第六步:測試
發現並沒有出現轉出實現了,轉入卻沒有實現的情況
註解方式的聲明式事務管理
第一步:引入aop的開發包
第二步:恢復轉賬環境
第三步:配置事務管理器
前三步和之前一樣
第四步:開啟註解事務
<tx:annotation-driven transaction-manager="transactionManager"/>
第五步:在業務層添加註解
只需要在AccountServiceImpl
類上面加@Transaction
註解即可
第六步:測試
發現並沒有出現轉出實現了,轉入卻沒有實現的情況