上一章我們簡單的介紹了swagger相關的實現,畢竟我都是直接貼程式碼了,確實也是挺簡單的,哈哈哈。 這一章我們主要介紹在springboot中的事務控制。
本專案的GitHub:https://github.com/pc859107393/Go2SpringBoot.git
有興趣交流springboot進行快速開發的同學可以加一下下面的企鵝群。
回顧事務控制
在傳統的Spring專案中,我們經典三層中主要在service層進行事務控制,常見的配置是什麼呢?具體實現如圖3.1所示。
圖3.1 傳統Spring專案的事務控制
在傳統的Spring專案中,我們的事務控制需要考慮如下幾點:
- 開啟事務管理
- 區別只讀事務和讀寫事務
- 配置Spring事務控制規則
- 找到service層的實現類
既然我們知道了傳統的事務控制我們需要做的事情,理解了這一點,我們也就可以在springboot專案中推測我們需要哪些東西。 ①. 事務控制相關依賴資源 ②. 事務管理開啟 ③.事務讀寫規則控制 ④.事務讀寫的實現.
在前面我們構建專案的時候已經加入了spring-boot-starter-aop
,所以依賴資源不是問題。接著我們需要編寫程式碼來實現相關的規則、開啟事務和實現事務。
首先我們可以上網查詢一下springboot相關的事務,無外乎都是懶人辦法直接在service方法上面新增註解@Transactional
和在入口類上面使用@EnableTransactionManagement
,這樣就能在專案中指定的方法上面開啟事務了。
但是有沒有一種更懶得方式呢?一定是有的,估計也是和Spring專案中類似。我們檢驗的標準是什麼?肯定是在service對應的方法內發生異常引起回滾操作。其他的原理不必解釋太多,先上碼。
@SpringBootApplication
@EnableWebMvc
@EnableSwagger2
@MapperScan(value = ["cn.acheng1314.base.dao"])
@Configuration
@EnableTransactionManagement
class BaseApplication : WebMvcConfigurer {
//事務型別引數
fun transactionAttributeSource(): TransactionAttributeSource {
val source = NameMatchTransactionAttributeSource()
//只讀或可寫事務
val readOnlyTx = RuleBasedTransactionAttribute()
readOnlyTx.isReadOnly = true
readOnlyTx.propagationBehavior = TransactionDefinition.PROPAGATION_SUPPORTS
//可寫事務
val requiredTx = RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED
, Collections.singletonList(RollbackRuleAttribute(Exception::class.java)))
val txMap = HashMap<String, TransactionAttribute>()
txMap["add*"] = requiredTx
txMap["save*"] = requiredTx
txMap["insert*"] = requiredTx
txMap["update*"] = requiredTx
txMap["delete*"] = requiredTx
txMap["get*"] = readOnlyTx
txMap["query*"] = readOnlyTx
txMap["find*"] = readOnlyTx
source.setNameMap(txMap)
return source
}
/*事務攔截器*/
@Bean(value = ["txInterceptor"])
fun getTransactionInterceptor(tx: PlatformTransactionManager): TransactionInterceptor {
return TransactionInterceptor(tx, transactionAttributeSource())
}
/**切面攔截規則 引數會自動從容器中注入 */
@Bean
fun pointcutAdvisor(txInterceptor: TransactionInterceptor): AspectJExpressionPointcutAdvisor {
val pointcutAdvisor = AspectJExpressionPointcutAdvisor()
pointcutAdvisor.advice = txInterceptor
pointcutAdvisor.expression = "execution (* cn.acheng1314.base.service.*ServiceImpl.*(..))"
return pointcutAdvisor
}
//省略其他程式碼
}
複製程式碼
在上面的事務規則引數中我們設定了兩邊倒事務(readOnlyTx,使用了TransactionDefinition.PROPAGATION_SUPPORTS
設定為兩邊倒事務)和可寫入事務(requiredTx)。接著我們在UserServiceImpl中寫一個發生異常的方法,測試是否能夠產生事務回滾,程式碼片段如下:
// @Transactional
@Throws(Exception::class)
fun addUser() {
val user = User()
user.duty = "aaa"
user.loginName = "aaa"
user.name = "aaa"
user.password = "aaa"
user.createDate = Date()
baseMapper.insert(user)
throw Exception("測試事務")
}
複製程式碼
我們來一點點程式碼進行單元測試,如下:
@RunWith(SpringJUnit4ClassRunner::class)
@SpringBootTest(classes = [BaseApplication::class])
class UserServiceImplTest {
@Autowired
private lateinit var userService: UserServiceImpl
@Test
fun addUserTest() {
userService.addUser()
}
}
複製程式碼
最後執行測試程式碼後,我們可以發現在資料庫中並沒有aaa這個使用者資訊存在,所以我們事務控制成功了。具體效果不用上圖了,大家都能在各自的資料庫工具中看到。