Closed huangxiuqi closed 8 months ago
Thanks for your feedback @huangxiuqi. I will investigate it, please assign me. @zhaojinchao95
Try to use Java API configuration, return DataSourceProxy directly, but it cannot be started,so this way doesn't work
@Configuration
public class ShardingSphereJdbcConfiguration {
@Bean
public DataSource dataSource() throws SQLException {
// 配置数据源
Map<String, DataSource> dataSourceMap = new HashMap<>();
dataSourceMap.put("ds0", createDataSource("seata_order0"));
dataSourceMap.put("ds1", createDataSource("seata_order1"));
List<RuleConfiguration> rules = Arrays.asList(
createShardingRuleConfiguration(),
createTransactionRuleConfiguration());
return ShardingSphereDataSourceFactory.createDataSource(
dataSourceMap, rules, new Properties());
}
private DataSource createDataSource(String name) {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/" + name + "?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8");
dataSource.setUsername("root");
dataSource.setPassword("root");
// return dataSource;
// 返回Seata代理数据源
return new DataSourceProxy(dataSource);
}
private ShardingRuleConfiguration createShardingRuleConfiguration() {
ShardingRuleConfiguration result = new ShardingRuleConfiguration();
// 添加分库分表规则
result.getTables().add(getOrderTableRuleConfiguration());
// 添加order_database_rule规则,按照user_id取余
Properties props1 = new Properties();
props1.setProperty("algorithm-expression", "ds${user_id % 2}");
result.getShardingAlgorithms().put(
"order_database_rule",
new AlgorithmConfiguration("INLINE", props1));
// 添加order_table_rule规则,按照order_id取余
Properties props2 = new Properties();
props2.setProperty("algorithm-expression", "order_tbl${id % 2}");
result.getShardingAlgorithms().put(
"order_table_rule",
new AlgorithmConfiguration("INLINE", props2));
// 添加snowflake规则,雪花算法生成id
result.getKeyGenerators().put(
"snowflake",
new AlgorithmConfiguration("SNOWFLAKE", new Properties()));
// 添加sharding_key_required_auditor规则,要求DML语句必须包含分片键
result.getAuditors().put(
"sharding_key_required_auditor",
new AlgorithmConfiguration("DML_SHARDING_CONDITIONS", new Properties()));
return result;
}
private TransactionRuleConfiguration createTransactionRuleConfiguration() {
return new TransactionRuleConfiguration("BASE", "Seata", new Properties());
}
private ShardingTableRuleConfiguration getOrderTableRuleConfiguration() {
// 分库分表命名规则 分ds0,ds1两个数据库,每个数据库各分t_order0,t_order1两个表
ShardingTableRuleConfiguration result = new ShardingTableRuleConfiguration("order_tbl", "ds${0..1}.order_tbl${0..1}");
// 根据user_id分库,规则名称order_database_rule
result.setDatabaseShardingStrategy(new StandardShardingStrategyConfiguration("user_id", "order_database_rule"));
// 根据order_id分表,规则名称order_table_rule
result.setTableShardingStrategy(new StandardShardingStrategyConfiguration("id", "order_table_rule"));
// order_id主键生成规则,规则名称snowflake
result.setKeyGenerateStrategy(new KeyGenerateStrategyConfiguration("id", "snowflake"));
// result.setAuditStrategy(new ShardingAuditStrategyConfiguration(Collections.singleton("sharding_key_required_auditor"), true));
return result;
}
}
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2022-11-23 17:19:19.112 ERROR 14876 --- [ main] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'orderDAO' defined in file [D:\MyProject\seata\seata\order\target\classes\com\example\order\dao\OrderDAO.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dataSourceScriptDatabaseInitializer' defined in class path resource [org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.class]: Unsatisfied dependency expressed through method 'dataSourceScriptDatabaseInitializer' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [com/example/order/config/ShardingSphereJdbcConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.sql.DataSource]: Factory method 'dataSource' threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:229) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1372) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1222) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:955) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.23.jar:5.3.23]
at org.springframework.context.support.AbstractApplicationContext.__refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.23.jar:5.3.23]
at org.springframework.context.support.AbstractApplicationContext.jrLockAndRefresh(AbstractApplicationContext.java:41002) ~[spring-context-5.3.23.jar:5.3.23]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:42008) ~[spring-context-5.3.23.jar:5.3.23]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) ~[spring-boot-2.7.5.jar:2.7.5]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734) ~[spring-boot-2.7.5.jar:2.7.5]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408) ~[spring-boot-2.7.5.jar:2.7.5]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) ~[spring-boot-2.7.5.jar:2.7.5]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-2.7.5.jar:2.7.5]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-2.7.5.jar:2.7.5]
at com.example.OrderApplication.main(OrderApplication.java:14) ~[classes/:na]
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dataSourceScriptDatabaseInitializer' defined in class path resource [org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.class]: Unsatisfied dependency expressed through method 'dataSourceScriptDatabaseInitializer' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [com/example/order/config/ShardingSphereJdbcConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.sql.DataSource]: Factory method 'dataSource' threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:541) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1391) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1311) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791) ~[spring-beans-5.3.23.jar:5.3.23]
... 21 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [com/example/order/config/ShardingSphereJdbcConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.sql.DataSource]: Factory method 'dataSource' threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:658) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:486) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1391) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1311) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791) ~[spring-beans-5.3.23.jar:5.3.23]
... 37 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.sql.DataSource]: Factory method 'dataSource' threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) ~[spring-beans-5.3.23.jar:5.3.23]
... 51 common frames omitted
Caused by: java.lang.NullPointerException: null
at org.apache.shardingsphere.infra.metadata.database.resource.ShardingSphereResourceMetaData.createDataSourceMetaDataMap(ShardingSphereResourceMetaData.java:64) ~[shardingsphere-infra-common-5.2.1.jar:5.2.1]
at org.apache.shardingsphere.infra.metadata.database.resource.ShardingSphereResourceMetaData.<init>(ShardingSphereResourceMetaData.java:53) ~[shardingsphere-infra-common-5.2.1.jar:5.2.1]
at org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase.createResourceMetaData(ShardingSphereDatabase.java:116) ~[shardingsphere-infra-common-5.2.1.jar:5.2.1]
at org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase.create(ShardingSphereDatabase.java:110) ~[shardingsphere-infra-common-5.2.1.jar:5.2.1]
at org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase.create(ShardingSphereDatabase.java:93) ~[shardingsphere-infra-common-5.2.1.jar:5.2.1]
at org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabasesFactory.createGenericDatabases(ShardingSphereDatabasesFactory.java:81) ~[shardingsphere-infra-common-5.2.1.jar:5.2.1]
at org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabasesFactory.create(ShardingSphereDatabasesFactory.java:69) ~[shardingsphere-infra-common-5.2.1.jar:5.2.1]
at org.apache.shardingsphere.mode.metadata.MetaDataContextsFactory.create(MetaDataContextsFactory.java:91) ~[shardingsphere-mode-core-5.2.1.jar:5.2.1]
at org.apache.shardingsphere.mode.metadata.MetaDataContextsFactory.create(MetaDataContextsFactory.java:69) ~[shardingsphere-mode-core-5.2.1.jar:5.2.1]
at org.apache.shardingsphere.mode.manager.standalone.StandaloneContextManagerBuilder.build(StandaloneContextManagerBuilder.java:49) ~[shardingsphere-standalone-mode-core-5.2.1.jar:5.2.1]
at org.apache.shardingsphere.driver.jdbc.core.datasource.ShardingSphereDataSource.createContextManager(ShardingSphereDataSource.java:76) ~[shardingsphere-jdbc-core-5.2.1.jar:5.2.1]
at org.apache.shardingsphere.driver.jdbc.core.datasource.ShardingSphereDataSource.<init>(ShardingSphereDataSource.java:64) ~[shardingsphere-jdbc-core-5.2.1.jar:5.2.1]
at org.apache.shardingsphere.driver.api.ShardingSphereDataSourceFactory.createDataSource(ShardingSphereDataSourceFactory.java:93) ~[shardingsphere-jdbc-core-5.2.1.jar:5.2.1]
at org.apache.shardingsphere.driver.api.ShardingSphereDataSourceFactory.createDataSource(ShardingSphereDataSourceFactory.java:77) ~[shardingsphere-jdbc-core-5.2.1.jar:5.2.1]
at org.apache.shardingsphere.driver.api.ShardingSphereDataSourceFactory.createDataSource(ShardingSphereDataSourceFactory.java:137) ~[shardingsphere-jdbc-core-5.2.1.jar:5.2.1]
at com.example.order.config.ShardingSphereJdbcConfiguration.dataSource(ShardingSphereJdbcConfiguration.java:37) ~[classes/:na]
at com.example.order.config.ShardingSphereJdbcConfiguration$$EnhancerBySpringCGLIB$$1.CGLIB$dataSource$0(<generated>) ~[classes/:na]
at com.example.order.config.ShardingSphereJdbcConfiguration$$EnhancerBySpringCGLIB$$1$$FastClassBySpringCGLIB$$1.invoke(<generated>) ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244) ~[spring-core-5.3.23.jar:5.3.23]
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) ~[spring-context-5.3.23.jar:5.3.23]
at com.example.order.config.ShardingSphereJdbcConfiguration$$EnhancerBySpringCGLIB$$1.dataSource(<generated>) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.3.23.jar:5.3.23]
... 52 common frames omitted
Try manually calling SeataTransactionHolder.set(GlobalTransactionContext.reload(RootContext.getXID())) in feign interceptor, but SeataTransactionHolder is not an public class...
Rewrite the SeataTransactionHolder class to make it public, add an interceptor and manually call SeataTransactionHolder.set(), it can work normally, but I don't know if it is correct.
public final class SeataTransactionHolder {
private SeataTransactionHolder() {
}
private static final ThreadLocal<GlobalTransaction> CONTEXT = new ThreadLocal<>();
/**
* Set seata global transaction.
*
* @param transaction global transaction context
*/
public static void set(final GlobalTransaction transaction) {
CONTEXT.set(transaction);
}
/**
* Get seata global transaction.
*
* @return global transaction
*/
public static GlobalTransaction get() {
return CONTEXT.get();
}
/**
* Clear global transaction.
*/
public static void clear() {
CONTEXT.remove();
}
}
@Configuration
public class SeataFeignInterceptorConfiguration implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SeataFeignInterceptor()).addPathPatterns("/**");
}
public static class SeataFeignInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String xid = RootContext.getXID();
if (xid == null) {
xid = request.getHeader(RootContext.KEY_XID);
}
if (!StringUtils.isBlank(xid) && SeataTransactionHolder.get() == null) {
RootContext.bind(xid);
SeataTransactionHolder.set(GlobalTransactionContext.getCurrentOrCreate());
}
return true;
}
}
}
Maybe according to the judgment whether it is in the transaction by SeataATShardingSphereTransactionManager#isInTransaction
, if RootContext.getXID()
is set outside shardingsphere,we can set call SeataTransactionHolder.set()
here to fix it.Of course a better design needs to be sorted out.
Same as mine,if i set the xid in transactionPropagationInterceptor of child-system, and the method is annotated with @ShardingSphereTransactionType(TransactionType.BASE), then it won't do "SeataTransactionHolder.set(globalTransaction);", finally NPE happend; if i don't set the xid from feign, in code 'GlobalTransactionContext.getCurrentOrCreate()' it will begin a new global transaction with different xid, i don't know why in this place it choose to get xid from RootContext,but before this code,"switch (connectionManager.getConnectionTransaction().getDistributedTransactionOperationType(autoCommit))" means you can't hold a xid, it confused me.
dependency:
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
<version>1.4.2</version>
<exclusions>
<exclusion>
<groupId>org.antlr</groupId>
<artifactId>antlr4-runtime</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-transaction-base-seata-at</artifactId>
<version>5.2.0</version>
</dependency>
Rewrite the SeataTransactionHolder class to make it public, add an interceptor and manually call SeataTransactionHolder.set(), it can work normally, but I don't know if it is correct.
public final class SeataTransactionHolder { private SeataTransactionHolder() { } private static final ThreadLocal<GlobalTransaction> CONTEXT = new ThreadLocal<>(); /** * Set seata global transaction. * * @param transaction global transaction context */ public static void set(final GlobalTransaction transaction) { CONTEXT.set(transaction); } /** * Get seata global transaction. * * @return global transaction */ public static GlobalTransaction get() { return CONTEXT.get(); } /** * Clear global transaction. */ public static void clear() { CONTEXT.remove(); } }
@Configuration public class SeataFeignInterceptorConfiguration implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new SeataFeignInterceptor()).addPathPatterns("/**"); } public static class SeataFeignInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String xid = RootContext.getXID(); if (xid == null) { xid = request.getHeader(RootContext.KEY_XID); } if (!StringUtils.isBlank(xid) && SeataTransactionHolder.get() == null) { RootContext.bind(xid); SeataTransactionHolder.set(GlobalTransactionContext.getCurrentOrCreate()); } return true; } } }
We also solved the problem in the same way, but we don't know if there will be other effects
重写 SeataTransactionHolder 类使其公开,添加一个拦截器并手动调用 SeataTransactionHolder.set(),它可以正常工作,但不知道是否正确。
public final class SeataTransactionHolder { private SeataTransactionHolder() { } private static final ThreadLocal<GlobalTransaction> CONTEXT = new ThreadLocal<>(); /** * Set seata global transaction. * * @param transaction global transaction context */ public static void set(final GlobalTransaction transaction) { CONTEXT.set(transaction); } /** * Get seata global transaction. * * @return global transaction */ public static GlobalTransaction get() { return CONTEXT.get(); } /** * Clear global transaction. */ public static void clear() { CONTEXT.remove(); } }
@Configuration public class SeataFeignInterceptorConfiguration implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new SeataFeignInterceptor()).addPathPatterns("/**"); } public static class SeataFeignInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String xid = RootContext.getXID(); if (xid == null) { xid = request.getHeader(RootContext.KEY_XID); } if (!StringUtils.isBlank(xid) && SeataTransactionHolder.get() == null) { RootContext.bind(xid); SeataTransactionHolder.set(GlobalTransactionContext.getCurrentOrCreate()); } return true; } } }
我们也以同样的方式解决了这个问题,但我们不知道是否会有其他影响
有在生产上检验过吗,我现在也打算这么去做了,我是在seata-dubbo拦截器里去做的,ApacheDubboTransactionPropagationFilter中加了
@huangxiuqi
org.apache.shardingsphere.transaction.annotation.ShardingSphereTransactionType
has been removed with the removal of Spring Boot Starter in #23724 .javax.transaction.Transactional
annotation or Jakarta EE 9+'s jakarta.transaction.Transactional
annotation? io.seata.spring.annotation.GlobalTransactional
annotation on ShardingSphere data sources. Refer to https://github.com/apache/incubator-seata-samples/tree/master/springcloud-seata-sharding-jdbc-mybatis-plus-samples for an explanation of this.但是这里要注意一个问题!!!!!! 虽然SeataATShardingTransactionManager和GlobalTransactionScanner做的事情一样,但是二者绝对不能混合使用!!!!!! 也就是说@ShardingTransactionType(TransactionType.BASE)和@GlobalTransactional绝对不能同时出现!!!!!! 看过上面SeataATShardingTransactionManager你就能明白,ShardingSphere把获取到的全局事务,放到了线程的局部变量里面了。而GlobalTransactionScanner则是采用动态代理的方式对方法进行增强。根本不能放在一起,杂交是要出问题的! ok!最终总结一句! 只要你的项目中用到sharding-jdbc,那么你全部微服务都需要导入seata整合sharding-jdbc的jar包 而且,你的项目中千万不能再出现@GlobalTransactional注解了,用SeataATShardingTransactionManager就可以了。
io.seata:seata-spring-boot-starter
. I personally tend to think that the current issue is essentially a documentation issue.
Question
Is there something wrong with my configuration? Demo https://github.com/huangxiuqi/SpringCloud-Seata-ShardingSphereJDBC
business service start a global transaction
order service, if remove @ShardingSphereTransactionType(TransactionType.BASE), no exception is thrown, but the transaction is not rollback
spring-cloud-starter-alibaba-seata will bind xid
in ConnectionTransaction.getDistributedTransactionOperationType(), transactionManager.isInTransaction() is true and will not call SeataATShardingSphereTransactionManager.begin(),