<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
JTA,全稱:Java Transaction API。JTA事務比JDBC事務更強大。一個JTA事務可以有多個參與者,而一個JDBC事務則被限定在一個單一的資料庫連線。所以,當我們在同時操作多個資料庫的時候,使用JTA事務就可以彌補JDBC事務的不足。
在Spring Boot 2.x中,整合了這兩個JTA的實現:
Atomikos:可以通過引入spring-boot-starter-jta-atomikos依賴來使用
Bitronix:可以通過引入spring-boot-starter-jta-bitronix依賴來使用
由於Bitronix自Spring Boot 2.3.0開始不推薦使用,所以在下面的動手環節中,我們將使用Atomikos作為例子來介紹JTA的使用。
XA協定是資料庫層面的一套分散式事務管理的規範,JTA是XA協定在Java中的實現,多個資料庫或是訊息廠商實現JTA介面,開發人員只需要呼叫SpringJTA介面即可實現JTA事務管理功能。
準備工作
這裡我們將使用最基礎的JdbcTemplate來實現資料存取,所以如果你還不會使用JdbcTemplate設定多資料來源,建議先看一JdbcTemplate的多資料來源設定。
場景設定:
假設我們有兩個庫,分別為:test1和test2
這兩個庫中都有一張User表,我們希望這兩張表中的資料是一致的
假設這兩張表中都已經有一條資料:name=aaa,age=30;因為這兩張表中資料是一致的,所以要update的時候,就必須兩個庫中的User表更新時候,要麼都成功,要麼都失敗。
<!--JTA元件核心依賴--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jta-atomikos</artifactId> </dependency>
yml組態檔這裡jtaManager的設定,在紀錄檔輸出中非常關鍵。
spring: jta: enabled: true transaction-manager-id: jtaManager datasource: username: root password: 123456 url: jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&allowPublicKeyRetrieval=true driver-class-name: com.mysql.jdbc.Driver backdatasource: username: root password: 123456 url: jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&allowPublicKeyRetrieval=true driver-class-name: com.mysql.jdbc.Driver
package com.sgcc.qfjs.config; import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.core.env.Environment; import org.springframework.jdbc.core.JdbcTemplate; import javax.sql.DataSource; @Configuration public class JtaDataSourceConfig { @Autowired private Environment env; @Autowired private DataSourceProperties properties; @Bean @Primary public DataSource primaryDatasource() { //資料庫連結 MysqlXADataSource mysqlXADataSource = new MysqlXADataSource(); mysqlXADataSource.setUrl(properties.getUrl()); mysqlXADataSource.setUser(properties.getUsername()); mysqlXADataSource.setPassword(properties.getPassword()); mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true); //事務管理 AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean(); atomikosDataSourceBean.setXaDataSource(mysqlXADataSource); atomikosDataSourceBean.setUniqueResourceName("dataSource"); return atomikosDataSourceBean; } @Bean public DataSource backDatasource() { //資料庫連結 MysqlXADataSource mysqlXADataSource = new MysqlXADataSource(); mysqlXADataSource.setUrl(env.getProperty("spring.backdatasource.url")); mysqlXADataSource.setUser(env.getProperty("spring.backdatasource.username")); mysqlXADataSource.setPassword(env.getProperty("spring.backdatasource.password")); mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true); //事務管理 AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean(); atomikosDataSourceBean.setXaDataSource(mysqlXADataSource); atomikosDataSourceBean.setUniqueResourceName("backDataSource"); return atomikosDataSourceBean; } @Bean("primaryTemplate") public JdbcTemplate primaryTemplate(){ return new JdbcTemplate(primaryDatasource()); } @Bean("backTemplate") public JdbcTemplate batchTemplate(){ return new JdbcTemplate(backDatasource()); } }
@Service @Slf4j public class CatTestServiceImpl extends ServiceImpl<CatTestMapper, CatTest> implements CatTestService { @Autowired private JdbcTemplate primaryTemplate; @Autowired private JdbcTemplate backTemplate; @Override @Transactional public void tx() { // 修改test1庫中的資料 primaryTemplate.update("update user set age = ? where name = ?", 40, "aaa"); // 修改test2庫中的資料 backTemplate.update("update user set age = ? where name = ?", 40, "aaa"); } @Override @Transactional public void tx2() { // 修改test1庫中的資料 primaryTemplate.update("update user set age = ? where name = ?", 50, "aaa"); // 模擬:修改test2庫之前丟擲異常 throw new RuntimeException(); } }
這裡tx函數,是兩句update操作,一般都會成功;而tx2函數中,我們人為的製造了一個異常,這個異常是在test1庫中的資料更新後才產生的,這樣就可以測試一下test1更新成功,之後是否還能在JTA的幫助下實現回滾。
package com.sgcc.qfjs.hsf; import com.sgcc.qfjs.module.service.CatTestService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class AppTest { @Autowired private CatTestService catTestService; @Test public void test1() throws Exception { // 正確更新的情況 catTestService.tx(); } @Test public void test2() throws Exception { // 更新失敗的情況 try { catTestService.tx2(); } catch (Exception e) { e.printStackTrace(); } } }
這裡有兩個測試用例:
test1:因為沒有故意製造的異常,不出意外兩個庫的update都會成功,所以根據name=aaa去把兩個資料查出來,看age是否都被更新到了40。
test2:tx2函數會把test1中name=aaa的使用者age更新為50,然後丟擲異常,JTA事務生效的話,會把age回滾回40,所以這裡的檢查也是兩個庫的aaa使用者的age應該都為50,這樣就意味著JTA事務生效,保證了test1和test2兩個庫中的User表資料更新一致,沒有製造出髒資料。
執行test1成功,檢視資料庫資料是否更新成功
執行test2成功,檢視資料庫資料是否回滾成功
2022-07-28 11:09:04.999|DEBUG|main|com.atomikos.logging.Slf4jLogger|Line:32| XAResource.rollback ( 6A74614D616E61676572313635383937373734343831353030303031:6A74614D616E6167657231 ) on resource dataSource represented by XAResource instance com.mysql.jdbc.jdbc2.optional.JDBC4SuspendableXAConnection@339b45f8
2022-07-28 11:09:05.010|DEBUG|main|com.atomikos.logging.Slf4jLogger|Line:32| rollback() done of transaction jtaManager165897774481500001
2022-07-28 11:09:05.010|DEBUG|main|com.atomikos.logging.Slf4jLogger|Line:32| rollback() done of transaction jtaManager165897774481500001
到此這篇關於SpringBoot2使用JTA元件實現基於JdbcTemplate多資料來源事務管理(親測好用)的文章就介紹到這了,更多相關SpringBoot2多資料來源事務管理內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45