最後附有網盤鏈接(程序打包+數據庫)
Spring 事務開發
^
^
1、Spring事務的概念與定義
Spring事務和數據庫中的事務其實是一樣的,也是回滾:
Spring事務其實就是Spring AOP,底層創建動態代理對象,在代碼的開頭結尾封裝了開啓事務和事務回滾操作。用過JDBC原生代碼的更應該清楚了,都是顯示在代理裏commit和rollback的。然後一大堆try catch…
Spring事務一般是針對Service的,回滾service的操作。
^
^
2、Spring事務的特性ACID
①原子性(atomicity):確保動作要麼全部完成要麼完全不起作用。
②一致性(consistency):數據和資源就處於一種滿足業務規則的一致性狀態中。
③隔離性(isolation): 用戶的操作不能混淆。
④持久性(durability): 一旦事務完成, 無論發生什麼系統錯誤, 它的結果都不應該受到影響。
^
^
3、事務的傳播行爲
^
^
4、事務隔離級別
事務的隔離級別要得到底層數據庫引擎的支持, 而不是應用程序或者框架的支持。事務的隔離級別有以下幾種:
ISOLATION_DEFAULT:這是默認值,表示使用底層數據庫的默認隔離級別。對大部分數據庫而言,通常這值就是。
ISOLATION_READ_UNCOMMITTED:該隔離級別表示一個事務可以讀取另一個事務修改但還沒有提交的數據。該級別不能防止髒讀和不可重複讀,因此很少使用該隔離級別。
ISOLATION_READ_COMMITTED:該隔離級別表示一個事務只能讀取另一個事務已經提交的數據。該級別可以防止髒讀,這也是大多數情況下的推薦值。
ISOLATION_REPEATABLE_READ:該隔離級別表示一個事務在整個過程中可以多次重複執行某個查詢,並且每次返回的記錄都相同。即使在多次查詢之間有新增的數據滿足該查詢,這些新增的記錄也會被忽略。該級別可以防止髒讀和不可重複讀。
ISOLATION_SERIALIZABLE:所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾,也就是說,該級別可以防止髒讀、不可重複讀以及幻讀。但是這將嚴重影響程序的性能。通常情況下也不會用到該級別。
Oracle 支持的 2 種事務隔離級別:READ_COMMITED , SERIALIZABLE
Mysql 支持 4 中事務隔離級別。
^
^
5、Spring事務三大接口介紹
1.PlatformTransactionManager(平臺)事務管理器
spring並不直接管理事務,而是提供了很多事務管理器,將事務管理職責委託給hibernate或者JTA等持久化機制所提供的相關平臺框架事務來實現。
spring事務管理器的接口是org.springframework.transaction.PlatformTransactionManager
通過這個接口,spring爲各個平臺如hibernate,jdbc等提供了對應的事務管理器,怎麼實現是各個平臺自己的事情了。
public interface PlatformTransactionManager extends TransactionManager {
//獲取事務狀態
TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
//事務提交
void commit(TransactionStatus var1) throws TransactionException;
//事務回滾
void rollback(TransactionStatus var1) throws TransactionException;
}
2.TransactionDefinition事務定義信息(事務傳播行爲,隔離級別,超時,只讀,回滾原則)
public interface TransactionDefinition {
//支持當前事務,若沒有事務則創建一個事務
int PROPAGATION_REQUIRED = 0;
//如果存在當前事務,則加入事務,如果沒有,則以非事務方式運行
int PROPAGATION_SUPPORTS = 1;
//如果存在當前事務,則加入事務,如果沒有,則拋出異常
int PROPAGATION_MANDATORY = 2;
//創建一個新的事務,如果存在當前事務,則當前事務掛起
int PROPAGATION_REQUIRES_NEW = 3;
//以非事務方式運行,如果存在當前事務,則當前事務掛起
int PROPAGATION_NOT_SUPPORTED = 4;
//以非事務方式運行,如果存在當前事務,則拋出異常
int PROPAGATION_NEVER = 5;
/**表示如果當前有一個事務正在運行中,則該方法應用運行在一個嵌套的事務中
*被嵌套的事務可以獨立運行於封裝的事務進行提交或者回滾(保存點)
*如果封裝事務不存在則 PROPAGATION_REQUIRES_NEW
**/
int PROPAGATION_NESTED = 6;
//使用後端數據庫默認的隔離級別,oracle默認讀已提交,mysql可重複度
int ISOLATION_DEFAULT = -1;
//最低的隔離級別,允許讀取尚未提交的數據變更,可能會導致幻讀、髒讀或者不可重複讀
int ISOLATION_READ_UNCOMMITTED = 1;
//允許讀取併發事務已經提交的數據,避免髒讀,但是不可避免幻讀或者不可重複讀
int ISOLATION_READ_COMMITTED = 2;
//對於多次讀取同一條記錄的結果是一致的,除非數據是被本身事務所修改,可以避免髒讀和不可重複度,幻讀可能發生
int ISOLATION_REPEATABLE_READ = 4;
//最高的隔離級別,完全服從ACID的隔離級別,所有的事務依次逐個執行,事務之間完全不可能產生干擾,避免髒讀,幻讀,不可重複度,但是性能最低
int ISOLATION_SERIALIZABLE = 8;
//使用默認的超時時間,事務進行時間大於設置時間就會拋異常,進行回滾
int TIMEOUT_DEFAULT = -1;
//獲取事務的傳播行爲
default int getPropagationBehavior() {
return 0;
}
//獲取事務的隔離級別
default int getIsolationLevel() {
return -1;
}
//獲取事務的超時時間
default int getTimeout() {
return -1;
}
//獲取事務的是否只讀
default boolean isReadOnly() {
return false;
}
//獲取事務的名稱
@Nullable
default String getName() {
return null;
}
static TransactionDefinition withDefaults() {
return StaticTransactionDefinition.INSTANCE;
}
}
final class StaticTransactionDefinition implements TransactionDefinition {
static final StaticTransactionDefinition INSTANCE = new StaticTransactionDefinition();
private StaticTransactionDefinition() {
}
}
3.TransactionStatus:事務運行狀態
用來記錄事務的狀態,該接口定義了一組方法,用來獲取或者判斷事務的狀態信息。
PlatformTransactionManager. getTransaction(…)返回一個TransactionStatus對象,返回的TransactionStatus對象可能代表一個新的或者已經存在的事務
public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {
boolean hasSavepoint();
void flush();
}
^
^
6、Spring代理方式靈活
^
^
7、實現方式兩個:編程式(XML配置和)、聲明註解式
7.1編程式
1、xml文件配置,
文件名/springtx/src/main/resources/config/applicationContext-program.xml
代碼
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
">
<!--
通過import 標籤引入其他上下文配置文件
-->
<import resource="applicationContext-jdbc.xml"/>
<bean id="stuCardDao" class="init.wuji.springboot.tx.program.StuCardDaoImpl">
<property name="jt" ref="jdbcTemplate"></property>
</bean>
<bean id="stuCardService" class="init.wuji.springboot.tx.program.StuCardServiceImpl">
<property name="scDao" ref="stuCardDao"></property>
<property name="transactionTemplate" ref="transactionTemplate"></property>
</bean>
</beans>
config文件還有其他部署文件,一會會上傳供大家測試。
另外一個文件呢是原來的springJDBC也做了更改
文件名:/springtx/src/main/resources/config/applicationContext-jdbc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
">
<!--
通過import 標籤引入其他上下文配置文件
-->
<import resource="applicationContext-jdbc.xml"/>
<bean id="stuCardDao" class="init.wuji.springboot.tx.program.StuCardDaoImpl">
<property name="jt" ref="jdbcTemplate"></property>
</bean>
<bean id="stuCardService" class="init.wuji.springboot.tx.program.StuCardServiceImpl">
<property name="scDao" ref="stuCardDao"></property>
<property name="transactionTemplate" ref="transactionTemplate"></property>
</bean>
</beans>
^
^
2、示例的類和接口的文件代碼
/springtx/src/main/java/init/wuji/springboot/tx/program/StuCardServiceImpl.java
package init.wuji.springboot.tx.program;
import java.math.BigDecimal;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import init.wuji.springboot.tx.exception.NoEnoughMoneyException;
public class StuCardServiceImpl implements StuCardService{
private StuCardDao scDao;
private TransactionTemplate transactionTemplate;
/**
* 轉賬支付,當金額不足時,拋出異常。
* @param targetCardNo 目標賬號
* @param sourceCardNo 源賬號
* @param money 轉賬金額
*/
public void transaferMoney(final String targetCardNo, final String sourceCardNo, final String money) {
transactionTemplate.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
StuCard sourceCard = scDao.getStuCardInfoById(sourceCardNo);
StuCard targetCard = scDao.getStuCardInfoById(targetCardNo);
//修改後勤人員信息
sourceCard.setMoney(sourceCard.getMoney().subtract(new BigDecimal(money)));
targetCard.setMoney(targetCard.getMoney().add(new BigDecimal(money)));
scDao.updateStuCardByCardNo(targetCard);
if(sourceCard.getMoney().compareTo(new BigDecimal("0")) < 0){
throw new NoEnoughMoneyException("賬戶餘額不足,請充值。。。。");
}
scDao.updateStuCardByCardNo(sourceCard);
System.out.println("支付完成!商品購買成功!!!!!");
return null;
}
});
}
/**
* @return the scDao
*/
public StuCardDao getScDao() {
return scDao;
}
/**
* @param scDao the scDao to set
*/
public void setScDao(StuCardDao scDao) {
this.scDao = scDao;
}
/**
* @return the transactionTemplate
*/
public TransactionTemplate getTransactionTemplate() {
return transactionTemplate;
}
/**
* @param transactionTemplate the transactionTemplate to set
*/
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
}
/springtx/src/main/java/init/wuji/springboot/tx/program/StuCardService.java
package init.wuji.springboot.tx.program;
public interface StuCardService {
/**
*
* @param targetCardNo
* @param sourceCardNo
* @param money
*/
public void transaferMoney(String targetCardNo, String sourceCardNo, String money);
}
MAIN方法(後臺的數據庫以及工程我給鏈接)
/springtx/src/main/java/init/wuji/springboot/tx/program/Main.java
package init.wuji.springboot.tx.program;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext ioc = new ClassPathXmlApplicationContext("config/applicationContext-program.xml");
StuCardService stuCardService = ioc.getBean(StuCardService.class);
stuCardService.transaferMoney("111", "222", "30");
}
}
7.2聲明註解式
類似於AOP操作
這個很省事,簡單的說一下,xml配置好了就ok。
applicationContext-anno-tx.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
">
<!--
通過import 標籤引入其他上下文配置文件
-->
<import resource="applicationContext-jdbc.xml"/>
<context:component-scan base-package="com.zzxtit.springboot.*.anno"></context:component-scan>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
applicationContext-xml-tx.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
">
<!--
通過import 標籤引入其他上下文配置文件
-->
<import resource="applicationContext-jdbc.xml"/>
<bean id="stuCardDao" class="com.zzxtit.springboot.tx.xml.StuCardDaoImpl">
<property name="jt" ref="jdbcTemplate"></property>
</bean>
<bean id="stuCardService" class="com.zzxtit.springboot.tx.xml.StuCardServiceImpl">
<property name="scDao" ref="stuCardDao"></property>
</bean>
<!--
事務傳播屬性的配置
-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="modify*" propagation="REQUIRED"/>
<tx:method name="edit*" propagation="REQUIRED"/>
<tx:method name="delet*" propagation="REQUIRED"/>
<tx:method name="transafer*" propagation="REQUIRED"/>
<tx:method name="query*" propagation="REQUIRED" read-only="true"/>
<tx:method name="select*" propagation="REQUIRED" read-only="true"/>
<tx:method name="find*" propagation="REQUIRED" read-only="true"/>
</tx:attributes>
</tx:advice>
<!--
事務的切入點配置
-->
<aop:config>
<aop:pointcut expression="execution(* com.zzxtit.springboot.*.xml.*.*(..))" id="txPointCut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
</beans>
主方法不變,StuCard.java不變
StuCardDao.java不變
剩下的加上註解@Repository和@Autowired
代碼打包下面給鏈接了
博主主頁已經上傳了資源。
鏈接
鏈接:https://pan.baidu.com/s/1_8Hs6V06GdX7ia5fYV4MlQ
提取碼:7s8u