javascript
014_Spring事务
一. 事務(wù)
1. 什么事務(wù)?
1.1. 事務(wù): 邏輯上的一組操作, 組成這組操作的各個單元, 要么全都成功, 要么全都失敗。
2. 事務(wù)的特性
2.1. 原子性: 事務(wù)不可分割。
2.2. 一致性: 事務(wù)執(zhí)行前后數(shù)據(jù)完整性保持一致。
2.3. 隔離性: 一個事務(wù)的執(zhí)行不應(yīng)該受到其他事務(wù)的干擾。
2.4. 持久性: 一旦事務(wù)結(jié)束, 數(shù)據(jù)就持久化到數(shù)據(jù)庫。
3. 如果不考慮隔離性引發(fā)安全性問題
3.1. 讀問題
3.1.1. 臟讀: 一個事務(wù)讀到另一個事務(wù)未提交的數(shù)據(jù)。
3.1.2. 不可重復(fù)讀: 一個事務(wù)讀到另一個事務(wù)已經(jīng)提交的update的數(shù)據(jù), 導(dǎo)致一個事務(wù)中多次查詢結(jié)果不一致。
3.1.3. 虛讀、幻讀: 一個事務(wù)讀到另一個事務(wù)已經(jīng)提交的insert的數(shù)據(jù), 導(dǎo)致一個事務(wù)中多次查詢結(jié)果不一致。
3.2. 寫問題
3.2.1. 丟失更新。
4. 設(shè)置事務(wù)的隔離級別解決讀問題
4.1. Read uncommitted: 未提交讀, 任何讀問題解決不了。
4.2. Read committed: 已提交讀, 解決臟讀, 但是不可重復(fù)讀和虛讀有可能發(fā)生。
4.3. Repeatable read: 重復(fù)讀, 解決臟讀、不可重復(fù)讀和幻讀(MySQL8中)。
4.4. Serializable: 解決所有讀問題, 同時似乎給整張表添加了一個鎖, 客戶并發(fā)讀, 但不能并發(fā)寫。
二. Spring的事務(wù)管理的API
1. PlatformTransactionManager平臺事務(wù)管理器接口
1.1. DataSourceTransactionManager: 底層使用JDBC管理事務(wù)。
1.2. HibernateTransactionManager: 底層使用Hibernate管理事務(wù)。
2. TransactionDefinition事務(wù)定義信息
2.1. 事務(wù)定義: 用于定義事務(wù)的相關(guān)的信息, 隔離級別、超時信息、傳播行為、是否只讀(只讀的時候不能寫)。
3. TransactionStatus事務(wù)的狀態(tài)
3.1. 事務(wù)狀態(tài): 用于記錄在事務(wù)管理過程中, 事務(wù)的狀態(tài)的對象。
4. 事務(wù)管理的API的關(guān)系
4.1. Spring進行事務(wù)管理的時候, 首先平臺事務(wù)管理器根據(jù)事務(wù)定義信息進行事務(wù)的管理, 在事務(wù)管理過程中, 產(chǎn)生各種狀態(tài), 將這些狀態(tài)的信息記錄到事務(wù)狀態(tài)的對象中。
5.?Spring中提供了七種事務(wù)的傳播行為:
5.1. 保證多個操作在同一個事務(wù)中
5.1.1. PROPAGATION_REQUIRED: 默認值, 如果A中有事務(wù), 使用A中的事務(wù), 如果A沒有, 創(chuàng)建一個新的事務(wù), 將操作包含進來。
5.1.2. PROPAGATION_SUPPORTS: 支持事務(wù), 如果A中有事務(wù), 使用A中的事務(wù)。如果A沒有事務(wù), 不使用事務(wù)。
5.1.3. PROPAGATION_MANDATORY: 如果A中有事務(wù), 使用A中的事務(wù)。如果A沒有事務(wù), 拋出異常。
5.2. 保證多個操作不在同一個事務(wù)中
5.2.1. PROPAGATION_REQUIRES_NEW: 如果A中有事務(wù), 將A的事務(wù)掛起(暫停), 創(chuàng)建新事務(wù), 只包含自身操作。如果A中沒有事務(wù), 創(chuàng)建一個新事務(wù), 包含自身操作。
5.2.2. PROPAGATION_NOT_SUPPORTED: 如果A中有事務(wù), 將A的事務(wù)掛起。不使用事務(wù)管理。
5.2.3. PROPAGATION_NEVER: 如果A中有事務(wù), 報異常。
5.3. 嵌套式事務(wù)
5.3.1. PROPAGATION_NESTED: 嵌套事務(wù), 如果A中有事務(wù), 按照A的事務(wù)執(zhí)行, 執(zhí)行完成后,設(shè)置一個保存點, 執(zhí)行B中的操作, 如果沒有異常, 執(zhí)行通過, 如果有異常, 可以選擇回滾到最初始位置, 也可以回滾到保存點。
三. 編程式事務(wù)
1. 配置平臺事務(wù)管理器
2. Spring提供了事務(wù)管理的模板類
3. 在業(yè)務(wù)層注入事務(wù)管理的模板
4. 編寫事務(wù)管理的代碼
5. 例子
5.1. 新建一個名為SpringJdbcProgramTx的Java工程, 拷入相關(guān)jar包
5.2. 新建一個Account.java
package com.lywgames.tx;import java.io.Serializable;public class Account implements Serializable {private static final long serialVersionUID = 1L;private Integer id;private String name;private Float money;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Float getMoney() {return money;}public void setMoney(Float money) {this.money = money;}@Overridepublic String toString() {return "Account [id=" + id + ", name=" + name + ", money=" + money + "]";}}5.3. 新建一個AccountDao.java數(shù)據(jù)庫操作接口
package com.lywgames.tx;/*** 轉(zhuǎn)賬的Dao的接口*/ public interface AccountDao {public void outMoney(String from, Float money);public void inMoney(String to, Float money); }5.4. 新建一個AccountDaoImpl.java數(shù)據(jù)庫操作實現(xiàn)類
package com.lywgames.tx;import org.springframework.jdbc.core.support.JdbcDaoSupport;/*** 轉(zhuǎn)賬的Dao的實現(xiàn)類*/ public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {@Overridepublic void outMoney(String from, Float money) {getJdbcTemplate().update("update account set money = money - ? where name = ?", money, from);}@Overridepublic void inMoney(String to, Float money) {getJdbcTemplate().update("update account set money = money + ? where name = ?", money, to);}}5.5. 新建一個AccountService.java業(yè)務(wù)接口
package com.lywgames.tx;/*** 轉(zhuǎn)賬的業(yè)務(wù)層的接口*/ public interface AccountService {public void transfer(String from, String to, Float money); }5.6. 新建一個AccountServiceImpl.java業(yè)務(wù)實現(xiàn)類
package com.lywgames.tx;import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate;/*** 轉(zhuǎn)賬的業(yè)務(wù)層的實現(xiàn)類*/ public class AccountServiceImpl implements AccountService {private AccountDao accountDao;public void setAccountDao(AccountDao accountDao) {this.accountDao = accountDao;}private TransactionTemplate transactionTemplate;public void setTransactionTemplate(TransactionTemplate transactionTemplate) {this.transactionTemplate = transactionTemplate;}/*** from: 轉(zhuǎn)出賬號* to: 轉(zhuǎn)入賬號* money: 轉(zhuǎn)賬金額*/@Overridepublic void transfer(String from, String to, Float money) {transactionTemplate.execute(new TransactionCallbackWithoutResult() {@Overrideprotected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {accountDao.outMoney(from, money);int d = 1/0;accountDao.inMoney(to, money);}});}}5.7. 新建一個Test.java測試類
package com.lywgames.tx;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {public static void main(String[] args) {ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");AccountService accountService = context.getBean(AccountService.class);accountService.transfer("王五", "李四", 100.00F);context.close();} }5.8. 在src目錄下創(chuàng)建jdbc.properties數(shù)據(jù)庫連接配置
5.9. 在src目錄下創(chuàng)建applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"><!-- 通過context標簽引入屬性文件 --><context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder><!-- 配置Spring內(nèi)置連接池 --><bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="${jdbc.driverClassName}"></property><property name="url" value="${jdbc.url}"></property><property name="username" value="${jdbc.username}"></property><property name="password" value="${jdbc.password}"></property></bean><!-- 配置平臺事務(wù)管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" /></bean><!-- 配置事務(wù)管理的模板 --><bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"><property name="transactionManager" ref="transactionManager" /></bean><!-- Dao繼承了JdbcDaoSupport, 可以不配置jdbcTemplate模板bean, 在注入dataSource屬性時, 會自動創(chuàng)建jdbcTemplate。 --><bean id="accountDao" class="com.lywgames.tx.AccountDaoImpl"><property name="dataSource" ref="dataSource"></property></bean><bean id="accountService" class="com.lywgames.tx.AccountServiceImpl"><property name="accountDao" ref="accountDao"></property><!-- 注入事務(wù)管理的模板 --><property name="transactionTemplate" ref="transactionTemplate" /></bean> </beans>5.10. 查看account表
5.11. 運行項目, 拋出異常, 查看數(shù)據(jù)庫結(jié)果, 轉(zhuǎn)載失敗, 每個人的錢數(shù)不變
5.12. 注釋掉異常, 運行項目, 查看數(shù)據(jù)庫結(jié)果, 轉(zhuǎn)賬成功
四. 聲明式事務(wù)管理(XML方式的聲明式事務(wù)管理)
1. 配置平臺事務(wù)管理器
2. 配置增強
3. AOP的配置
4. 例子
4.1. 新建一個名為SpringJdbcXmlTx的Java工程, 拷入相關(guān)jar包
4.2. 新建一個Account.java
package com.lywgames.tx;import java.io.Serializable;public class Account implements Serializable {private static final long serialVersionUID = 1L;private Integer id;private String name;private Float money;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Float getMoney() {return money;}public void setMoney(Float money) {this.money = money;}@Overridepublic String toString() {return "Account [id=" + id + ", name=" + name + ", money=" + money + "]";}}4.3. 新建一個AccountDao.java數(shù)據(jù)庫操作接口
package com.lywgames.tx;/*** 轉(zhuǎn)賬的Dao的接口*/ public interface AccountDao {public void outMoney(String from, Float money);public void inMoney(String to, Float money); }4.4. 新建一個AccountDaoImpl.java數(shù)據(jù)庫操作實現(xiàn)類
package com.lywgames.tx;import org.springframework.jdbc.core.support.JdbcDaoSupport;/*** 轉(zhuǎn)賬的Dao的實現(xiàn)類*/ public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {@Overridepublic void outMoney(String from, Float money) {getJdbcTemplate().update("update account set money = money - ? where name = ?", money, from);}@Overridepublic void inMoney(String to, Float money) {getJdbcTemplate().update("update account set money = money + ? where name = ?", money, to);}}4.5. 新建一個AccountService.java業(yè)務(wù)接口
package com.lywgames.tx;/*** 轉(zhuǎn)賬的業(yè)務(wù)層的接口*/ public interface AccountService {public void transfer(String from, String to, Float money); }4.6. 新建一個AccountServiceImpl.java業(yè)務(wù)實現(xiàn)類
package com.lywgames.tx;/*** 轉(zhuǎn)賬的業(yè)務(wù)層的實現(xiàn)類*/ public class AccountServiceImpl implements AccountService {private AccountDao accountDao;public void setAccountDao(AccountDao accountDao) {this.accountDao = accountDao;}/*** from: 轉(zhuǎn)出賬號* to: 轉(zhuǎn)入賬號* money: 轉(zhuǎn)賬金額*/@Overridepublic void transfer(String from, String to, Float money) {accountDao.outMoney(from, money);int d = 1/0;accountDao.inMoney(to, money);}}4.7. 新建一個Test.java測試類
package com.lywgames.tx;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {public static void main(String[] args) {ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");AccountService accountService = context.getBean(AccountService.class);accountService.transfer("王五", "李四", 100.00F);context.close();} }4.8. 在src目錄下創(chuàng)建jdbc.properties數(shù)據(jù)庫連接配置
4.9. 在src目錄下創(chuàng)建applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"><!-- 通過context標簽引入屬性文件 --><context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder><!-- 配置Spring內(nèi)置連接池 --><bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="${jdbc.driverClassName}"></property><property name="url" value="${jdbc.url}"></property><property name="username" value="${jdbc.username}"></property><property name="password" value="${jdbc.password}"></property></bean><!-- 配置事務(wù)管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean><!-- Dao繼承了JdbcDaoSupport, 可以不配置jdbcTemplate模板bean, 在注入dataSource屬性時, 會自動創(chuàng)建jdbcTemplate。 --><bean id="accountDao" class="com.lywgames.tx.AccountDaoImpl"><property name="dataSource" ref="dataSource"></property></bean><bean id="accountService" class="com.lywgames.tx.AccountServiceImpl"><property name="accountDao" ref="accountDao"></property></bean> <!-- 配置事務(wù)的增強/通知, 類似前置通知、后置通知等。 --><tx:advice id="txAdvice" transaction-manager="transactionManager"><tx:attributes><!-- name="*" 表示所有方法 --><tx:method name="*" propagation="REQUIRED" read-only="false"/></tx:attributes></tx:advice><!-- aop的配置 --><aop:config><aop:pointcut expression="execution(* com.lywgames.tx.AccountServiceImpl.*(..))" id="pointcut"/><!-- aop:advisor和aop:aspect都是切面。aop:advisor多個切入點和多個通知的組合。aop:aspect一個切入點和一個通知的組合。 --><aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/></aop:config> </beans>4.10. 查看account表
4.11. 運行項目, 拋出異常, 查看數(shù)據(jù)庫結(jié)果, 轉(zhuǎn)載失敗, 每個人的錢數(shù)不變
4.12. 注釋掉異常, 運行項目, 查看數(shù)據(jù)庫結(jié)果, 轉(zhuǎn)賬成功
五. 聲明式事務(wù)管理(注解方式的聲明式事務(wù)管理)
1. 配置平臺事務(wù)管理器
2. 開啟注解事務(wù)
3. 在業(yè)務(wù)層添加注解
4. 例子
4.1. 新建一個名為SpringJdbcAnnotationTx的Java工程, 拷入相關(guān)jar包
4.2. 新建一個Account.java
package com.lywgames.tx;import java.io.Serializable;public class Account implements Serializable {private static final long serialVersionUID = 1L;private Integer id;private String name;private Float money;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Float getMoney() {return money;}public void setMoney(Float money) {this.money = money;}@Overridepublic String toString() {return "Account [id=" + id + ", name=" + name + ", money=" + money + "]";}}4.3. 新建一個AccountDao.java數(shù)據(jù)庫操作接口
package com.lywgames.tx;/*** 轉(zhuǎn)賬的Dao的接口*/ public interface AccountDao {public void outMoney(String from, Float money);public void inMoney(String to, Float money); }4.4. 新建一個AccountDaoImpl.java數(shù)據(jù)庫操作實現(xiàn)類
package com.lywgames.tx;import javax.annotation.Resource; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component;/*** 轉(zhuǎn)賬的Dao的實現(xiàn)類*/ @Component(value="accountDao") public class AccountDaoImpl implements AccountDao {@Resource(name="jdbcTemplate")private JdbcTemplate jdbcTemplate;@Overridepublic void outMoney(String from, Float money) {jdbcTemplate.update("update account set money = money - ? where name = ?", money, from);}@Overridepublic void inMoney(String to, Float money) {jdbcTemplate.update("update account set money = money + ? where name = ?", money, to);}}4.5. 新建一個AccountService.java業(yè)務(wù)接口
package com.lywgames.tx;/*** 轉(zhuǎn)賬的業(yè)務(wù)層的接口*/ public interface AccountService {public void transfer(String from, String to, Float money); }4.6. 新建一個AccountServiceImpl.java業(yè)務(wù)實現(xiàn)類
package com.lywgames.tx;import javax.annotation.Resource; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional;/*** 轉(zhuǎn)賬的業(yè)務(wù)層的實現(xiàn)類*/ @Transactional @Component(value="accountService") public class AccountServiceImpl implements AccountService {@Resource(name="accountDao")private AccountDao accountDao;/*** from: 轉(zhuǎn)出賬號* to: 轉(zhuǎn)入賬號* money: 轉(zhuǎn)賬金額*/@Overridepublic void transfer(String from, String to, Float money) {accountDao.outMoney(from, money);int d = 1/0;accountDao.inMoney(to, money);}}4.7. 新建一個Test.java測試類
package com.lywgames.tx;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {public static void main(String[] args) {ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");AccountService accountService = context.getBean(AccountService.class);accountService.transfer("王五", "李四", 100.00F);context.close();} }4.8. 在src目錄下創(chuàng)建jdbc.properties數(shù)據(jù)庫連接配置
4.9. 在src目錄下創(chuàng)建applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"><!-- 使用IOC的注解開發(fā), 配置組件掃描, 哪些包下的類使用了IOC的注解 --><context:component-scan base-package="com.lywgames"></context:component-scan><!-- 通過context標簽引入屬性文件 --><context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder><!-- 配置Spring內(nèi)置連接池 --><bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="${jdbc.driverClassName}"></property><property name="url" value="${jdbc.url}"></property><property name="username" value="${jdbc.username}"></property><property name="password" value="${jdbc.password}"></property></bean><!-- 配置事務(wù)管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean><!-- 開啟注解事務(wù) --><tx:annotation-driven transaction-manager="transactionManager"/><!-- 配置Spring的Jdbc模板 --><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"></property></bean> </beans>4.10. 查看account表
4.11. 運行項目, 拋出異常, 查看數(shù)據(jù)庫結(jié)果, 轉(zhuǎn)載失敗, 每個人的錢數(shù)不變
4.12. 注釋掉異常, 運行項目, 查看數(shù)據(jù)庫結(jié)果, 轉(zhuǎn)賬成功
《新程序員》:云原生和全面數(shù)字化實踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的014_Spring事务的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 013_JDBC模板使用第三方连接池
- 下一篇: 001_SpringMVC入门