在Spring Boot中,當我們使用了spring-boot-starter-jdbc或spring-boot-starter-data-jpa依賴的時候碟贾,框 架會自動默認分別注入DataSourceTransactionManager或JpaTransactionManager。所以我們不需要任何額外 配置就可以用@Transactional注解進行事務的使用缕陕。
spring Boot 使用事務非常簡單,首先使用注解 @EnableTransactionManagement 開啟事務支持后扛邑,然后在訪問數據庫的Service方法上添加注解 @Transactional 便可怜浅。
開啟事務
- @EnableTransactionManagement 開啟事務支持
- 在Service方法上添加注解 @Transactional
@EnableTransactionManagement
@SpringBootApplication(scanBasePackages = "zmx.springboot")
public class Application {
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean save(StUser entity) {
// 其它邏輯
boolean result = super.save(entity);
// 其它邏輯
throw new RuntimeException("測試的異常");
}
多個事務管理器
SpringBoot為我們自動做了蔬崩,對我們并不透明,如果有多個事務管理器沥阳,需要手動指定怎么處理@Transactional的value具體指定使用哪個事務管理器
/**
* 多個事務管理
*/
@Configuration
public class MyTransactionManagementConfigurer implements TransactionManagementConfigurer {
@Autowired
@Qualifier("txManager1")
private PlatformTransactionManager txManager1;
/**
* 創(chuàng)建一個自己的事務管理器
*
* @param dataSource
* @return
*/
@Bean(name = "txManager1")
public PlatformTransactionManager txManager1(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "txManager2")
public PlatformTransactionManager txManager2(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
/**
* 其返回值代表在擁有多個事務管理器的情況下默認使用的事務管理器
*
* @return
*/
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
return txManager1;
}
}
@Transactional(rollbackFor = Exception.class, value = "txManager2")
@Override
public boolean save(StUser entity) {
boolean result = super.save(entity);
throw new RuntimeException("測試的異常");
}
指定隔離級別
隔離級別是指若干個并發(fā)的事務之間的隔離程度,與我們開發(fā)時候主要相關的場景包括:臟讀取桐罕、重復讀桂敛、幻讀。org.springframework.transaction.annotation.Isolation枚舉類中定義了五個表示隔離級別的值:
public enum Isolation {
/**
* 這是默認值术唬,表示使用底層數據庫的默認隔離級別。對大部分數據庫而言滚澜,通常這值就是: READ_COMMITTED
*/
DEFAULT(TransactionDefinition.ISOLATION_DEFAULT),
/**
* 該隔離級別表示一個事務可以讀取另一個事務修改但還沒有提交的數據。該級別不能防止臟讀和不可重復讀设捐。
*/
READ_UNCOMMITTED(TransactionDefinition.ISOLATION_READ_UNCOMMITTED),
/**
* 該隔離級別表示一個事務只能讀取另一個事務已經提交的數據。該級別可以防止臟讀萝招,這也是大多數情況下的推薦值。
*/
READ_COMMITTED(TransactionDefinition.ISOLATION_READ_COMMITTED),
/**
* 該隔離級別表示一個事務在整個過程中可以多次重復執(zhí)行某個查詢槐沼,并且每次返回的記錄都相同橡淆。即使在多次查詢之間有新增的數據滿足該查詢母赵,這些新增的記錄也會被忽略逸爵。該級別可以防止臟讀和不可重復讀凹嘲。
*/
REPEATABLE_READ(TransactionDefinition.ISOLATION_REPEATABLE_READ),
/**
* 所有的事務依次逐個執(zhí)行,這樣事務之間就完全不可能產生干擾周蹭,也就是說趋艘,該級別可以防止臟讀凶朗、不可重復讀以及幻讀瓷胧。但是這將嚴重影響程序的性能棚愤。通常情況下也不會用到該級別搓萧。
*/
SERIALIZABLE(TransactionDefinition.ISOLATION_SERIALIZABLE);
}
指定方法:通過使用 isolation
屬性設置宛畦,例如:
@Transactional(isolation = Isolation.DEFAULT)
事務的傳播行為
傳播行為是指,如果在開始當前事務之前次和,一個事務上下文已經存在反肋,此時有若干選項可以指定一個事務性方法的執(zhí)行行為踏施。
public enum Propagation {
/**
* 如果當前存在事務石蔗,則加入該事務;如果當前沒有事務养距,則創(chuàng)建一個新的事務
*/
REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),
/**
* 如果當前存在事務,則加入該事務铃在;如果當前沒有事務碍遍,則以非事務的方式繼續(xù)運行定铜。
*/
SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),
/**
* 如果當前存在事務怕敬,則加入該事務揣炕;如果當前沒有事務东跪,則拋出異常畸陡。
*/
MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),
/**
* 創(chuàng)建一個新的事務虽填,如果當前存在事務丁恭,則把當前事務掛起斋日。
*/
REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),
/**
* 以非事務方式運行牲览,如果當前存在事務恶守,則把當前事務掛起第献。
*/
NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),
/**
* 以非事務方式運行兔港,如果當前存在事務庸毫,則拋出異常衫樊。
*/
NEVER(TransactionDefinition.PROPAGATION_NEVER),
/**
* 如果當前存在事務飒赃,則創(chuàng)建一個事務作為當前事務的嵌套事務來運行科侈;如果當前沒有事務盒揉,則該取值等價于 REQUIRED
*/
NESTED(TransactionDefinition.PROPAGATION_NESTED);
}
指定方法:通過使用 propagation
屬性設置兑徘,例如:
@Transactional(propagation = Propagation.REQUIRED)
事務實現機制
在應用系統調用聲明了 @Transactional 的目標方法時,Spring Framework 默認使用 AOP 代理挂脑,在代碼運行時生成一個代理對象藕漱,根據 @Transactional 的屬性配置信息,這個代理對象決定該聲明 @Transactional 的目標方法是否由攔截器 TransactionInterceptor 來使用攔截肋联,在 TransactionInterceptor 攔截時,會在目標方法開始執(zhí)行之前創(chuàng)建并加入事務橄仍,并執(zhí)行目標方法的邏輯, 最后根據執(zhí)行情況是否出現異常,利用抽象事務管理器 AbstractPlatformTransactionManager 操作數據源 DataSource 提交或回滾事務侮繁。
TransactionTemplate
在spring-boot-autoconfigure.jar自動裝配了TransactionTemplate
@Configuration
@ConditionalOnClass({PlatformTransactionManager.class})
@AutoConfigureAfter({JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, Neo4jDataAutoConfiguration.class})
@EnableConfigurationProperties({TransactionProperties.class})
public class TransactionAutoConfiguration {
// ...
@Bean
@ConditionalOnMissingBean
public TransactionTemplate transactionTemplate() {
return new TransactionTemplate(this.transactionManager);
}
}
try {
transactionTemplate.execute(transactionStatus -> {
//...
// 通過拋出異常來回滾事務
throw new RuntimeException("模擬插入記錄后失敗, 檢查是否回滾");
});
} catch (Exception e) {
System.out.println("Transaction rolled back");
}