SpringBoot2-第三章:springboot的事務控制

pc859107393發表於2018-06-05

上一章我們簡單的介紹了swagger相關的實現,畢竟我都是直接貼程式碼了,確實也是挺簡單的,哈哈哈。 這一章我們主要介紹在springboot中的事務控制。

本專案的GitHub:https://github.com/pc859107393/Go2SpringBoot.git

有興趣交流springboot進行快速開發的同學可以加一下下面的企鵝群。

行走的java全棧

回顧事務控制

在傳統的Spring專案中,我們經典三層中主要在service層進行事務控制,常見的配置是什麼呢?具體實現如圖3.1所示。

圖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這個使用者資訊存在,所以我們事務控制成功了。具體效果不用上圖了,大家都能在各自的資料庫工具中看到。

相關文章