雖然現在微服務越來越流行,我們的系統隨之也拆分出來好多的模塊功能。這樣做的目的其實就是為了彌補單體架構中存在的不足。隨着微服務的拆分,肯定設計到分庫分表,但這之中肯定設計到分布式事務。最典型的例子就是銀行轉賬,比如銀行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 去進行事務的一致性管理。等以后研究了再來跟大家分享。
