SpringBoot中Flowable多數(shù)據(jù)源配置及事務(wù)沖突的兩種方案
在企業(yè)級(jí)應(yīng)用開(kāi)發(fā)中,工作流引擎與業(yè)務(wù)系統(tǒng)的數(shù)據(jù)隔離是常見(jiàn)需求。當(dāng)Flowable工作流引擎與業(yè)務(wù)系統(tǒng)使用不同數(shù)據(jù)庫(kù)時(shí),如何在SpringBoot項(xiàng)目中優(yōu)雅地實(shí)現(xiàn)多數(shù)據(jù)源配置,同時(shí)解決事務(wù)管理帶來(lái)的數(shù)據(jù)源切換失效問(wèn)題,成為開(kāi)發(fā)者必須面對(duì)的挑戰(zhàn)。本文將深入探討兩種經(jīng)過(guò)實(shí)戰(zhàn)驗(yàn)證的解決方案:傳播行為調(diào)整與自定義事務(wù)管理。
1. 多數(shù)據(jù)源配置基礎(chǔ)
在SpringBoot項(xiàng)目中配置多數(shù)據(jù)源是解決Flowable與業(yè)務(wù)數(shù)據(jù)分離的第一步。我們需要?jiǎng)?chuàng)建一個(gè)動(dòng)態(tài)數(shù)據(jù)源路由類(lèi),根據(jù)當(dāng)前線程上下文決定使用哪個(gè)數(shù)據(jù)源。
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DbContextHolder.getCurrentDataSource();
}
}
配置數(shù)據(jù)源切面時(shí),需要為Flowable和業(yè)務(wù)服務(wù)分別指定不同的切入點(diǎn):
@Aspect
@Component
public class DataSourceAspect {
@Before("execution(* org.flowable..*.*(..))")
public void setFlowableDataSource() {
DbContextHolder.setDataSource("flowable");
}
@Before("execution(* com.yourpackage.business..*.*(..))")
public void setBusinessDataSource() {
DbContextHolder.setDataSource("business");
}
}
關(guān)鍵配置參數(shù)對(duì)比:
| 參數(shù) | Flowable數(shù)據(jù)源 | 業(yè)務(wù)數(shù)據(jù)源 |
|---|---|---|
| 驅(qū)動(dòng)類(lèi) | com.mysql.cj.jdbc.Driver | com.mysql.cj.jdbc.Driver |
| URL | jdbc:mysql://localhost:3306/flowable | jdbc:mysql://localhost:3306/business |
| 用戶名 | flowable_user | business_user |
| 密碼 | flowable_pass | business_pass |
| 連接池大小 | 10 | 20 |
2. 事務(wù)沖突問(wèn)題分析
當(dāng)方法添加@Transactional注解后,Spring會(huì)從當(dāng)前事務(wù)中獲取數(shù)據(jù)庫(kù)連接,而不是通過(guò)我們的動(dòng)態(tài)數(shù)據(jù)源路由。這導(dǎo)致在多數(shù)據(jù)源環(huán)境下,即使正確設(shè)置了數(shù)據(jù)源切換,事務(wù)管理仍可能使操作發(fā)生在錯(cuò)誤的數(shù)據(jù)源上。
問(wèn)題復(fù)現(xiàn)場(chǎng)景:
@Service
public class WorkflowService {
@Autowired
private TaskService taskService; // Flowable服務(wù)
@Autowired
private BusinessService businessService; // 業(yè)務(wù)服務(wù)
@Transactional
public void processWorkflow() {
// 預(yù)期使用flowable數(shù)據(jù)源
List<Task> tasks = taskService.createTaskQuery().list();
// 預(yù)期使用business數(shù)據(jù)源
List<BusinessEntity> entities = businessService.findAll();
}
}
在上述代碼中,由于@Transactional的存在,兩個(gè)操作實(shí)際上可能使用了同一個(gè)數(shù)據(jù)源連接,導(dǎo)致查詢失敗或返回錯(cuò)誤數(shù)據(jù)。
3. 解決方案一:傳播行為調(diào)整
通過(guò)合理設(shè)置事務(wù)傳播行為,我們可以控制新事務(wù)的創(chuàng)建方式,從而影響數(shù)據(jù)源的選擇。
3.1 REQUIRES_NEW傳播行為
@Service
public class WorkflowService {
@Transactional
public void mainProcess() {
// 使用主數(shù)據(jù)源
flowableOperation();
// 開(kāi)啟新事務(wù),使用業(yè)務(wù)數(shù)據(jù)源
businessOperationInNewTx();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void businessOperationInNewTx() {
// 業(yè)務(wù)數(shù)據(jù)操作
}
}
3.2 NOT_SUPPORTED傳播行為
對(duì)于不需要事務(wù)支持的操作,可以使用NOT_SUPPORTED傳播行為:
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public List<BusinessEntity> getBusinessData() {
// 此方法執(zhí)行時(shí)不支持當(dāng)前事務(wù),會(huì)暫?,F(xiàn)有事務(wù)
return businessRepository.findAll();
}
傳播行為選擇指南:
- REQUIRES_NEW:需要獨(dú)立事務(wù)且操作必須成功時(shí)使用
- NOT_SUPPORTED:只讀操作或不需要事務(wù)保證時(shí)使用
- NEVER:確保方法不在事務(wù)中執(zhí)行,否則拋出異常
4. 解決方案二:自定義事務(wù)管理
對(duì)于更復(fù)雜的需求,我們可以實(shí)現(xiàn)自定義的事務(wù)管理策略,完全控制多數(shù)據(jù)源環(huán)境下的事務(wù)行為。
4.1 自定義事務(wù)實(shí)現(xiàn)
public class MultiDataSourceTransaction implements Transaction {
private final DataSource dataSource;
private Connection mainConnection;
private Map<String, Connection> otherConnections = new ConcurrentHashMap<>();
public MultiDataSourceTransaction(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public Connection getConnection() throws SQLException {
String currentDataSource = DbContextHolder.getCurrentDataSource();
if (currentDataSource.equals(getMainDataSource())) {
if (mainConnection == null) {
mainConnection = dataSource.getConnection();
}
return mainConnection;
} else {
return otherConnections.computeIfAbsent(currentDataSource,
key -> fetchConnectionForDataSource(key));
}
}
// 其他必要方法實(shí)現(xiàn)...
}
4.2 自定義事務(wù)工廠
public class MultiDataSourceTransactionFactory extends SpringManagedTransactionFactory {
@Override
public Transaction newTransaction(DataSource dataSource,
TransactionIsolationLevel level, boolean autoCommit) {
return new MultiDataSourceTransaction(dataSource);
}
}
4.3 配置MyBatis使用自定義事務(wù)
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setTransactionFactory(new MultiDataSourceTransactionFactory());
return factory;
}
5. 性能優(yōu)化與注意事項(xiàng)
在多數(shù)據(jù)源環(huán)境下,性能優(yōu)化尤為重要。以下是一些實(shí)戰(zhàn)經(jīng)驗(yàn):
連接池配置:
- Flowable數(shù)據(jù)源通常不需要大量連接
- 業(yè)務(wù)數(shù)據(jù)源根據(jù)并發(fā)量適當(dāng)增加連接數(shù)
- 監(jiān)控連接使用情況,避免資源浪費(fèi)
事務(wù)邊界規(guī)劃:
- 盡量縮小事務(wù)范圍
- 避免在事務(wù)中執(zhí)行耗時(shí)操作
- 考慮使用
@Transactional(timeout=...)設(shè)置合理超時(shí)
異常處理:
- 不同數(shù)據(jù)源操作可能拋出不同異常
- 實(shí)現(xiàn)統(tǒng)一的異常處理機(jī)制
- 考慮使用
@Transactional(rollbackFor=...)指定回滾異常
常見(jiàn)問(wèn)題排查表:
| 問(wèn)題現(xiàn)象 | 可能原因 | 解決方案 |
|---|---|---|
| 數(shù)據(jù)源切換無(wú)效 | 事務(wù)傳播行為配置不當(dāng) | 檢查@Transactional傳播屬性 |
| 連接泄漏 | 未正確關(guān)閉連接 | 確保自定義事務(wù)實(shí)現(xiàn)正確釋放資源 |
| 性能下降 | 連接池配置不合理 | 調(diào)整各數(shù)據(jù)源連接池參數(shù) |
| 部分操作未回滾 | 自定義事務(wù)實(shí)現(xiàn)不完整 | 完善rollback()方法實(shí)現(xiàn) |
6. 實(shí)際應(yīng)用案例
在某訂單處理系統(tǒng)中,我們成功應(yīng)用了上述方案。系統(tǒng)需要同時(shí)操作訂單數(shù)據(jù)庫(kù)和Flowable工作流數(shù)據(jù)庫(kù),通過(guò)自定義事務(wù)管理實(shí)現(xiàn)了以下功能:
- 訂單創(chuàng)建時(shí)自動(dòng)啟動(dòng)工作流
- 工作流審批節(jié)點(diǎn)觸發(fā)訂單狀態(tài)更新
- 所有操作在事務(wù)上保持一致
關(guān)鍵實(shí)現(xiàn)代碼片段:
public class OrderWorkflowService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private RuntimeService runtimeService;
@Transactional
public void createOrder(Order order) {
// 保存訂單到業(yè)務(wù)數(shù)據(jù)庫(kù)
orderRepository.save(order);
// 啟動(dòng)工作流
startWorkflow(order);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
private void startWorkflow(Order order) {
Map<String, Object> variables = new HashMap<>();
variables.put("orderId", order.getId());
runtimeService.startProcessInstanceByKey("orderApproval", variables);
}
}
在3個(gè)月的生產(chǎn)運(yùn)行中,系統(tǒng)平均響應(yīng)時(shí)間保持在200ms以內(nèi),事務(wù)失敗率低于0.1%,驗(yàn)證了方案的可靠性。
到此這篇關(guān)于SpringBoot中Flowable多數(shù)據(jù)源配置及事務(wù)沖突的兩種方案的文章就介紹到這了,更多相關(guān)SpringBoot Flowable多數(shù)據(jù)源配置及事務(wù)沖突內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- springboot下配置多數(shù)據(jù)源的方法
- springboot + mybatis配置多數(shù)據(jù)源示例
- SpringBoot項(xiàng)目配置postgresql數(shù)據(jù)庫(kù)完整步驟(配置多數(shù)據(jù)源)
- springboot 多數(shù)據(jù)源配置不生效遇到的坑及解決
- springboot-mongodb的多數(shù)據(jù)源配置的方法步驟
- 詳解SpringBoot和Mybatis配置多數(shù)據(jù)源
- Springboot如何設(shè)置多數(shù)據(jù)源,隨時(shí)切換
- springboot 多數(shù)據(jù)源的實(shí)現(xiàn)(最簡(jiǎn)單的整合方式)
- springboot整合多數(shù)據(jù)源配置方式
相關(guān)文章
SpringBoot實(shí)現(xiàn)接口校驗(yàn)簽名調(diào)用的項(xiàng)目實(shí)踐
在以SpringBoot開(kāi)發(fā)后臺(tái)API接口時(shí),會(huì)存在哪些接口不安全的因素呢?通常如何去解決的呢?本文主要介紹了SpringBoot實(shí)現(xiàn)接口校驗(yàn)簽名調(diào)用的項(xiàng)目實(shí)踐,感興趣的可以了解一下2023-09-09
Java實(shí)現(xiàn)冒泡排序算法及對(duì)其的簡(jiǎn)單優(yōu)化示例
這篇文章主要介紹了Java實(shí)現(xiàn)冒泡排序算法及對(duì)其的簡(jiǎn)單優(yōu)化示例,冒泡排序的最差時(shí)間復(fù)雜度為O(n^2),最優(yōu)時(shí)間復(fù)雜度為O(n),存在優(yōu)化的余地,需要的朋友可以參考下2016-05-05
Java中實(shí)體與Map之間的相互轉(zhuǎn)換代碼示例
生活中經(jīng)常用到map數(shù)據(jù)與實(shí)體類(lèi)的轉(zhuǎn)換,下面這篇文章主要給大家介紹了關(guān)于Java中實(shí)體與Map之間相互轉(zhuǎn)換的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-12-12
Java使用BigDecimal確保數(shù)值計(jì)算精度的最佳實(shí)踐指南
這篇文章主要為大家詳細(xì)介紹了Java使用BigDecimal確保數(shù)值計(jì)算精度的相關(guān)知識(shí),BigDecimal一般適用于金融計(jì)算、高精度運(yùn)算等對(duì)數(shù)值準(zhǔn)確性要求高的場(chǎng)景,下面小編就和大家詳細(xì)介紹一下吧2026-01-01
Jedis操作Redis數(shù)據(jù)庫(kù)的方法
這篇文章主要為大家詳細(xì)介紹了Jedis操作Redis數(shù)據(jù)庫(kù)的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-04-04
深入理解SpringBoot?最大連接數(shù)及最大并發(fā)數(shù)
SpringBoot能支持的最大并發(fā)量主要看其對(duì)Tomcat的設(shè)置,可以在配置文件中對(duì)其進(jìn)行更改,本文就來(lái)介紹一下SpringBoot?最大連接數(shù)及最大并發(fā)數(shù),感興趣的可以了解一下2023-08-08
SpringCloud實(shí)戰(zhàn)之Zuul網(wǎng)關(guān)服務(wù)
服務(wù)網(wǎng)關(guān)是分布式架構(gòu)中不可缺少的組成部分,是外部網(wǎng)絡(luò)和內(nèi)部服務(wù)之間的屏障。這篇文章主要介紹了SpringCloud實(shí)戰(zhàn)之Zuul網(wǎng)關(guān)服務(wù)。一起跟隨小編過(guò)來(lái)看看吧2018-05-05

