本文源碼 GitHub地址:知了一笑 https://github.com/cicadasmile/spring-boot-base
一、事務基本概念
一組業務操做ABCD,要麼所有成功,要麼所有不成功。
二、特性:ACID
原子性:總體
一致性:完成
隔離性:併發
持久性:結果
三、隔離問題
髒讀:一個事務讀到另外一個事務沒有提交的數據
不可重複讀:一個事務讀到另外一個事務已提交的數據(update)
虛讀(幻讀):一個事務讀到另外一個事務已提交的數據(insert)
四、隔離級別
read uncommitted:讀未提交。
read committed:讀已提交。解決髒讀。
repeatable read:可重複讀。解決:髒讀、不可重複讀。
serializable :串行化。都解決,單事務。java
1)PlatformTransactionManager
平臺事務管理器,spring要管理事務,必須使用事務管理器進行事務配置時,必須配置事務管理器。
2)TransactionDefinition
事務詳情(事務定義、事務屬性),spring用於肯定事務具體詳情,
例如:隔離級別、是否只讀、超時時間 等
進行事務配置時,必須配置詳情。spring將配置項封裝到該對象實例。
3)TransactionStatus
事務狀態,spring用於記錄當前事務運行狀態。例如:是否有保存點,事務是否完成。
spring底層根據狀態進行相應操做。git
PROPAGATION_REQUIRED , required , 必須 【默認值】 支持當前事務,A若是有事務,B將使用該事務。 若是A沒有事務,B將建立一個新的事務。 PROPAGATION_SUPPORTS ,supports ,支持 支持當前事務,A若是有事務,B將使用該事務。 若是A沒有事務,B將以非事務執行。 PROPAGATION_MANDATORY,mandatory ,強制 支持當前事務,A若是有事務,B將使用該事務。 若是A沒有事務,B將拋異常。 PROPAGATION_REQUIRES_NEW , requires_new ,必須新的 若是A有事務,將A的事務掛起,B建立一個新的事務 若是A沒有事務,B建立一個新的事務 PROPAGATION_NOT_SUPPORTED ,not_supported ,不支持 若是A有事務,將A的事務掛起,B將以非事務執行 若是A沒有事務,B將以非事務執行 PROPAGATION_NEVER ,never,從不 若是A有事務,B將拋異常 若是A沒有事務,B將以非事務執行 PROPAGATION_NESTED ,nested ,嵌套 A和B底層採用保存點機制,造成嵌套事務。 掌握:PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED
基於轉帳的案例演示,基於druid鏈接池配置。druid鏈接池在文章。github
SpringBoot2.0 基礎案例(07):集成Druid鏈接池,配置監控界面
CREATE TABLE account( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50), money INT )ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO account(username,money) VALUES('jack','10000'); INSERT INTO account(username,money) VALUES('rose','10000'); SELECT * FROM account;
該配置用於測試事務的手動管理。spring
/** * 事物管理器 */ @Bean(name = "transactionManager") public PlatformTransactionManager transactionManager (DruidDataSource dataSource){ LOGGER.info("【transactionManager 初始化...】"); DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(); transactionManager.setDataSource(dataSource); return transactionManager; } /** * 建立事物手動管理模板 */ @Bean(name = "transactionTemplate") public TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) LOGGER.info("【transactionTemplate 初始化...】"); TransactionTemplate transactionTemplate = new TransactionTemplate() ; transactionTemplate.setTransactionManager(transactionManager); return transactionTemplate; }
接口方法sql
public interface AccountService { /** * 匯款 */ void out (String outer , Integer money); /** * 收款 */ void in (String inner , Integer money); }
接口實現併發
@Service public class AccountServiceImpl implements AccountService { @Resource private JdbcTemplate jdbcTemplate ; public void out(String outer, Integer money) { String sql = "update account set money = money - ? where username = ?"; jdbcTemplate.update(sql, money,outer); } public void in(String inner, Integer money) { String sql = "update account set money = money + ? where username = ?"; jdbcTemplate.update(sql, money,inner); } }
測試接口ide
public interface TradeService { /** * 轉帳交易:沒有事務管理 */ void trade1(String outer ,String inner ,Integer money); /** * 轉帳交易:手動管理事務 */ void trade2(String outer ,String inner ,Integer money); /** * 轉帳交易:註解管理事務 */ void trade3(String outer ,String inner ,Integer money); }
接口實現spring-boot
@Service public class TradeServiceImpl implements TradeService { @Resource private AccountService accountService ; @Resource private TransactionTemplate transactionTemplate ; @Override public void trade1(String outer, String inner, Integer money) { accountService.out(outer, money); // 拋出異常 int i = 1/0; accountService.in(inner, money); } @Override public void trade2(String outer, String inner, Integer money) { transactionTemplate.execute(new TransactionCallbackWithoutResult() { public void doInTransactionWithoutResult(TransactionStatus arg0) { accountService.out(outer, money); // 拋出異常 int i = 1/0; accountService.in(inner, money); } }); } @Transactional(value="transactionManager",propagation= Propagation.REQUIRED) @Override public void trade3(String outer, String inner, Integer money) { accountService.out(outer, money); // 拋出異常 int i = 1/0; accountService.in(inner, money); } }
@RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = TransactionApplication.class) public class TradeTest { @Resource private TradeService tradeService ; /** * 沒有事務管理 * jack 減小了1000塊錢,可是rose獲得1000塊錢 * 1 jack 9000 * 2 rose 10000 */ @Test public void testTrade1 (){ tradeService.trade1("jack", "rose", 1000); } /** * 手動管理事務 * 1 jack 10000 * 2 rose 10000 */ @Test public void testTrade2 (){ tradeService.trade2("jack", "rose", 1000); } /** * 註解管理事務 * 1 jack 10000 * 2 rose 10000 */ @Test public void testTrade3 (){ tradeService.trade3("jack", "rose", 1000); } }
GitHub地址:知了一笑 https://github.com/cicadasmile/spring-boot-base 碼雲地址:知了一笑 https://gitee.com/cicadasmile/spring-boot-base