Closed yeruilong closed 3 months ago
@yeruilong Can you show a demo? I'll check it.
The following are the main Class
1、 @Configuration @MapperScan(basePackages = "com.xx.cloud.uc.admin.mapper", sqlSessionFactoryRef = "sqlSessionFactory") public class DataSourceConfig {
@Resource
@Qualifier("shardingDataSource")
private DataSource dataSource;
@Bean
public DataSourceSwitch dataSourceSwitch() {
Map<Object, Object> targetDataSources = new HashMap<>();
return new DataSourceSwitch(dataSource, targetDataSources);
}
@Bean
public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSourceSwitch") DataSource dynamicDataSource) throws Exception {
MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
bean.setDataSource(dynamicDataSource);
return bean.getObject();
}
@Bean(name = "sqlSessionFactory")
public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
2、 @Slf4j public class DataSourceSwitch extends AbstractRoutingDataSource {
public final Map<Object, Object> dataSources;
/**
* 动态数据源构造器
*
* @param defaultDataSource 默认数据源
* @param targetDataSource 目标数据源映射
*/
public DataSourceSwitch(DataSource defaultDataSource,Map<Object, Object> targetDataSource) {
dataSources = targetDataSource;
super.setDefaultTargetDataSource(defaultDataSource);
// 存放数据源的map
super.setTargetDataSources(dataSources);
// afterPropertiesSet 的作用很重要,它负责解析成可用的目标数据源
super.afterPropertiesSet();
}
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceContextHolder.get();
}
public void addDataSource(DatasourceDto datasource) {
HikariDataSource dataSource = new HikariDataSource();
String jdbcUrl = "jdbc:mysql://" +
datasource.getHost() +
":" +
datasource.getPort() +
"/" +
datasource.getDbName() +
"?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true";
dataSource.setJdbcUrl(jdbcUrl);
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUsername(datasource.getUsername());
dataSource.setPassword(datasource.getPwd());
dataSource.setMaximumPoolSize(3);
dataSource.setIdleTimeout(30000);
dataSource.setMinimumIdle(3);
// 将传入的数据源对象放入动态数据源类的静态map中,然后再讲静态map重新保存进动态数据源中
dataSources.putIfAbsent(datasource.getDbCode(), dataSource);
super.setTargetDataSources(dataSources);
super.afterPropertiesSet();
}
}
3、
public class DynamicDataSourceContextHolder {
private static final ThreadLocal<String> contextHolder = new InheritableThreadLocal<>();
public static void set(String dbType) {
contextHolder.set(dbType);
}
public static String get() {
return contextHolder.get();
}
public static void remove() {
contextHolder.remove();
}
}
4、 @Service @Slf4j public class BusinessConfigServiceImpl extends ServiceImpl<BusinessConfigMapper, BusinessConfig> implements BusinessConfigService {
@Resource
private BusinessConfigMapper businessConfigMapper;
@Override
@ShardingTransactionType(TransactionType.XA)
@Transactional
public Boolean updateBusinessConfig() {
LambdaQueryWrapper<BusinessConfig> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(BusinessConfig::getId, 1);
// DynamicDataSourceContextHolder.get();
BusinessConfig businessConfig = businessConfigMapper.selectOne(wrapper);
businessConfig.setType(1111);
businessConfigMapper.updateById(businessConfig);
// DynamicDataSourceContextHolder.remove();
BusinessConfigServiceImpl businessConfigServiceImpl = SpringContextUtil.getBean("businessConfigServiceImpl", BusinessConfigServiceImpl.class);
businessConfigServiceImpl.updateBusinessConfig2();
//int l = 1 / 0;
return true;
}
@Override
//@ShardingTransactionType(TransactionType.XA)
@Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class)
public Boolean updateBusinessConfig2() {
// 切换数据源
DataSourceSwitch dataSourceSwitch = SpringContextUtil.getBean("dataSourceSwitch", DataSourceSwitch.class);
DatasourceDto datasourcedto = new DatasourceDto();
datasourcedto.setHost("127.0.0.1");
datasourcedto.setPort(3306);
datasourcedto.setUsername("root");
datasourcedto.setPwd("123456");
datasourcedto.setDbName("uc-center");
datasourcedto.setDbCode("localhost");
datasourcedto.setBelongCode("localhost");
dataSourceSwitch.addDataSource(datasourcedto);
DynamicDataSourceContextHolder.set(datasourcedto.getDbCode());
LambdaQueryWrapper<BusinessConfig> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(BusinessConfig::getId, 1);
// DynamicDataSourceContextHolder.get();
BusinessConfig businessConfig = businessConfigMapper.selectOne(wrapper);
businessConfig.setType(3333);
//int l = 1 / 0;
int count = businessConfigMapper.updateById(businessConfig);
DynamicDataSourceContextHolder.remove();
//int l = 1 / 0;
return true;
}
}
@yeruilong It seems that the usage scenario is the same as the issue and now there are some problems with the XA
transaction interface.
I think there are some misunderstands of ShardingTransactionType
with TransactionType.XA
. It is an internal transaction used by sharding-shpere to coordinate the distributed backend databases. @yeruilong if you have only one dataSource, can you check if it works by removing @ShardingTransactionType(TransactionType.XA)
?
if i retain one database,and removing @ShardingTransactionType(TransactionType.XA),transaction not effective,it must contain @ShardingTransactionType(TransactionType.XA) and @Transactional then transation can work.can you add me qq/weixin?qq:269365937 vx:dhbsz999
Hello , this issue has not received a reply for several days. This issue is supposed to be closed.
There hasn't been any activity on this issue recently, and in order to prioritize active issues, it will be marked as stale.
@ShardingTransactionType(TransactionType.XA) @transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class) public Boolean A() { mapperA.updateById(); B(); }
@transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class) public Boolean b() { mapperB.updateById(); } WARN com.atomikos.datasource.xa.XAResourceTransaction - XA resource 'resource-1-master': suspend for XID '3139322E3136382E35362E312E746D313633383237323939323830323030303031:3139322E3136382E35362E312E746D31' raised -5: invalid arguments were given for the XA operation com.mysql.cj.jdbc.MysqlXAException: XAER_INVAL: Invalid arguments (or unsupported command)
when I call interface reported an error, but no solution was found