雖然現在微服務越來越流行,我們的系統隨之也拆分出來好多的模塊功能。這樣做的目的其實就是為了彌補單體架構中存在的不足。隨着微服務的拆分,肯定設計到分庫分表,但這之中肯定設計到分布式事務。最典型的例子就是銀行轉賬,比如銀行A給銀行B轉賬500 塊錢,流程肯定是銀行A-500,銀行B+500,在這個過程要么都成功,要么都成仁。首先銀行A和銀行B的數肯定是在不同的數據庫,如果在轉賬的過程中,銀行A首先-500庫錢之后,在銀行B+500的時候出現了問題,如果事務不回滾,那么就會出現500塊錢丟失的問題,也就是出現了事務一致性問題。
JTA + Atomikos解決分布式事務
一、JTA
JTA(java Transaction API)是JavaEE 13 個開發規范之一。Java 事務API,允許應用程序執行分布式事務處理——在兩個或多個網絡計算機資源上訪問並且更新數據。JDBC驅動程序的JTA支持極大地增強了數據訪問能力。事務最簡單最直接的目的就是保證數據的有效性,數據的一致性。
二、Atomikos
Atomikos是一個為Java平台提供增值服務的並且開源類事務管理器。
工作原理:分布式事務包括事務管理器和支持XA的資源管理器。資源管理器就是我們的DB,事務管理器就是承擔調節和控制所有參與DB所設計到的事務。
個人理解:Atomikos 獲取到數據庫的連接之后,會屏蔽數據庫底層的事務控制,然后全部交給 Atomikos,進行統一的調度和控制。
接下來,我們簡單的做一個基於 SpringBoot 的分布式事務控制。
1、首先我們要引入需要引入的maven庫
1
2
3
4
5
|
<
font
style
=
"color:rgb(77, 77, 77)"
>
<
font
face
=
"""
>
<
font
style
=
"font-size:16px"
>
<
!
--分布式事務-->
<
dependency
>
<
groupId
>
org.springframework.boot
<
/
groupId
>
<
artifactId
>
spring
-
boot
-
starter
-
jta
-
atomikos
<
/
artifactId
>
<
/
dependency
>
<
/
font
>
<
/
font
>
<
/
font
>
|
2、配置數據源
3、配置類
最主要的配置
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
<
font
style
=
"color:rgb(77, 77, 77)"
>
<
font
face
=
"""
>
<
font
style
=
"font-size:16px"
>
@Configuration
@MapperScan
(
basePackages
=
"com.example.mapper.db1"
,
sqlSessionFactoryRef
=
"db1SqlSessionFactory"
)
public
class
DB
1
DataSourcesConfig
{
@Primary
@Bean
(
name
=
"db1DataSource"
)
public DataSource dataSource
(
DB
1
Config DB
1
Config
)
{
/
/
設置數據庫連接
MysqlXADataSource mysqlXADataSource
=
new
MysqlXADataSource
(
)
;
mysqlXADataSource.setUrl
(
DB
1
Config.getUrl_jdbc
(
)
)
;
mysqlXADataSource.setUser
(
DB
1
Config.getUsername
(
)
)
;
mysqlXADataSource.setPassword
(
DB
1
Config.getPassword
(
)
)
;
mysqlXADataSource.setPinGlobalTxToPhysicalConnection
(
true
)
;
/
/
交給事務管理器進行管理
AtomikosDataSourceBean atomikosDataSourceBean
=
new
AtomikosDataSourceBean
(
)
;
atomikosDataSourceBean.setXaDataSource
(
mysqlXADataSource
)
;
atomikosDataSourceBean.setUniqueResourceName
(
"db1DataSource"
)
;
return
atomikosDataSourceBean;
}
@Primary
@Bean
(
name
=
"db1SqlSessionFactory"
)
public SqlSessionFactory sqlSessionFactory
(
@Qualifier
(
"db1DataSource"
)
DataSource dataSource
)
throws Exception
{
SqlSessionFactoryBean sessionFactoryBean
=
new
SqlSessionFactoryBean
(
)
;
sessionFactoryBean.setDataSource
(
dataSource
)
;
sessionFactoryBean.setMapperLocations
(
new
PathMatchingResourcePatternResolver
(
)
.getResources
(
"classpath*:/mapper/db1/*.xml"
)
)
;
org.apache.ibatis.session.Configuration
configuration
=
new
org.apache.ibatis.session.Configuration
(
)
;
configuration
.setMapUnderscoreToCamelCase
(
true
)
;
sessionFactoryBean.setConfiguration
(
configuration
)
;
return
sessionFactoryBean.getObject
(
)
;
}
@Primary
@Bean
(
name
=
"db1SqlSessionTemplate"
)
public SqlSessionTemplate sqlSessionTemplate
(
@Qualifier
(
"db1SqlSessionFactory"
)
SqlSessionFactory sqlSessionFactory
)
{
return
new
SqlSessionTemplate
(
sqlSessionFactory
)
;
}
}
<
/
font
>
<
/
font
>
<
/
font
>
|
這樣基本就配置完了,這里我只寫了一個數據庫的配置,另外一個同這個一樣,就是數據庫信息變了而已。
4、測試
這里設計到兩個數據的修改,學生姓名和學生分數成績,這兩個數據分別存儲在不同的數據庫。我們通過接口先修改用戶信息,接着再修改用戶的分數信息。
沒有修改前的數據
我們先沒不加事務,先看下如果再修改分數的時候出現異常,用戶信息會不會回滾回去。
結果
首先代碼在39行報錯,如果按照我們的邏輯,如果修改分數失敗,那么相應的用戶的年齡修改也是不成功的,但是結果顯示用戶的年齡還是被修改了,顯然這個接口並沒有被分布式事務所管理。
我們先把數據改回原來,然后我們再把事務加上,看還不會出現這種問題。(方法上加@Transactional注解即可)
結果
加了分布式事務之后,通過結果就可以看到,如果后面的結果出現了錯誤,前面的數據也是會進行回滾的,保證了事務的前后一致性,確保了數據的安全准確。
總結:以上就是 JTA + Atomikos 實現分布式事務的整個過程,相對實現功能來說還是比較簡單的,以上的測試是基於單個的 SpringBoot 項目的,相對於真正的微服務來說,這樣的方式我還沒有進行測試,如果需要進行微服務之間的事務管理,也可以通過 mq 或者 dubbo 去進行事務的一致性管理。等以后研究了再來跟大家分享。