Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

springCloud服务使用@LocalTcc未生效或报错显示 #7047

Open
wxrqforever opened this issue Dec 4, 2024 · 5 comments
Open

springCloud服务使用@LocalTcc未生效或报错显示 #7047

wxrqforever opened this issue Dec 4, 2024 · 5 comments
Labels
type: bug Category issues or prs related to bug.

Comments

@wxrqforever
Copy link

wxrqforever commented Dec 4, 2024

一、相关组件版本

        <dependency>
            <groupId>org.apache.seata</groupId>
            <artifactId>seata-spring-boot-starter</artifactId>
            <version>>2.1.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-client</artifactId>
            <version>2.4.2</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
            <version>2021.0.6.1</version>
            <exclusions>
                <exclusion>
                    <groupId>io.seata</groupId>
                    <artifactId>seata-spring-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
seata-server:2.1 

二、问题描述
业务想接入改造成TCC,所以先用一个简单的例子验证一下特性,发现一直达不到效果。

1.tcc相关注解在接口

代码如下:

public class GlobalTransactionTestController {
   @GetMapping("/testTcc")
    @GlobalTransactional
    public ResultGeneralModel<Boolean> testTcc() {
        log.info("测试tcc事务务");
        tccTestService.prepare(null,123);
        int i = 1/0;
        return ResultGeneralModel.newSuccess(Boolean.TRUE);
    }
}
@LocalTCC
public interface TccTestService {
    @TwoPhaseBusinessAction(name = "TccTestBean", commitMethod = "commit", rollbackMethod = "rollback")
    void prepare(BusinessActionContext actionContext,@BusinessActionContextParameter(paramName = "a") int a);;

    void commit(BusinessActionContext actionContext);


    void rollback(BusinessActionContext actionContext);
}
@Component
@Slf4j
public class TccTestServiceImpl implements TccTestService {

    @Override
    public void prepare(BusinessActionContext actionContext, int a) {
        //一些访问db的动作,省略了,非常简单
        log.info("prepare 被调用");
    }

    @Override
    public void commit(BusinessActionContext actionContext) {
        log.info("commit 被调用");

    }

    @Override
    public void rollback(BusinessActionContext actionContext) {
        log.info("rollback 被调用");

    }
}

启动正常,tcc resource注册成功:

INFO org.apache.seata.core.rpc.netty.RmNettyRemotingClient [main] [] [] will register resourceId:TccTestBean

代码执行后报错,报错日志:

2024-12-04 20:56:12.615 ERROR[http-nio-8080-exec-1] [] [] java.lang.NoSuchMethodException: org.springframework.aop.SpringProxy.prepare(org.apache.seata.rm.tcc.api.BusinessActionContext, int)
java.lang.RuntimeException: java.lang.NoSuchMethodException: org.springframework.aop.SpringProxy.prepare(org.apache.seata.rm.tcc.api.BusinessActionContext, int)
	at org.apache.seata.rm.tcc.interceptor.TccActionInterceptorHandler.lambda$parseAnnotation$0(TccActionInterceptorHandler.java:118)
	at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660)
	at org.apache.seata.rm.tcc.interceptor.TccActionInterceptorHandler.parseAnnotation(TccActionInterceptorHandler.java:103)
	at org.apache.seata.rm.tcc.interceptor.TccActionInterceptorHandler.doInvoke(TccActionInterceptorHandler.java:71)
	at org.apache.seata.integration.tx.api.interceptor.handler.AbstractProxyInvocationHandler.invoke(AbstractProxyInvocationHandler.java:43)
	at org.apache.seata.spring.annotation.AdapterSpringSeataInterceptor.invoke(AdapterSpringSeataInterceptor.java:44)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708)
	at xxx.TccTestServiceImpl$$EnhancerBySpringCGLIB$$953891f3.prepare(<generated>)
	at xxxxx.seata.GlobalTransactionTestController.testTcc(GlobalTransactionTestController.java:77)
	at xxxxx.seata.GlobalTransactionTestController$$FastClassBySpringCGLIB$$14f5a059.invoke(<generated>)

debug定位了一下报错的地方,这里拿到的接口是SpringProxy,八成是spring代理的,这个接口里肯定是没有的preapre
org.apache.seata.rm.tcc.interceptor.TccActionInterceptorHandler#parseAnnotation

image

2.tcc相关注解在实现类
看了和tcc使用的相关issue,怀疑是注解的位置导致的,因此我将注解移动到了实现类中,

public interface TccTestService {
    void prepare(BusinessActionContext actionContext, int a);;

    void commit(BusinessActionContext actionContext);


    void rollback(BusinessActionContext actionContext);
}
@Component
@Slf4j
@LocalTCC
public class TccTestServiceImpl implements TccTestService {

    @Override
    @TwoPhaseBusinessAction(name = "TccTestBean", commitMethod = "commit", rollbackMethod = "rollback")
    public void prepare(BusinessActionContext actionContext, @BusinessActionContextParameter(paramName = "a") int a) {
        //一些访问db的动作,省略了,非常简单
        log.info("prepare 被调用");
    }

    @Override
    public void commit(BusinessActionContext actionContext) {
        log.info("commit 被调用");

    }

    @Override
    public void rollback(BusinessActionContext actionContext) {
        log.info("rollback 被调用");

    }
}

启动后,虽然tm 和rm注册成功. 但是并没有看到tcc resource注册成功的这条日志:

INFO org.apache.seata.core.rpc.netty.RmNettyRemotingClient [main] [] [] will register resourceId:TccTestBean

代码执行后,确实返回了/ by zero异常,但是cacnel方法并没有被回调。

甚至isLocalTCC都没有命中:

   private boolean isLocalTCC(Class<?> classType) {
        Set<Class<?>> interfaceClasses = ReflectionUtil.getInterfaces(classType);
        for (Class<?> interClass : interfaceClasses) {
            if (interClass.isAnnotationPresent(LocalTCC.class)) {
                return true;
            }
        }
        return classType.isAnnotationPresent(LocalTCC.class);
    }

以上,希望能得到帮助,多谢!

@slievrly
Copy link
Member

slievrly commented Dec 8, 2024

thanks for your feedback.

@slievrly slievrly added the type: bug Category issues or prs related to bug. label Dec 8, 2024
@wxrqforever
Copy link
Author

请问这个问题计划会在哪个版本的到修复

@wxrqforever
Copy link
Author

@funky-eyes 老哥 这个有计划修复的时间吗?是否有其他使用方式可以规避,或者有修复的大体方案,我这边也可以尝试修复,我这的业务需要使用localtcc的模式的需求,多谢帮忙看看。

@funky-eyes
Copy link
Contributor

你可以提供一个稳定复现的最小demo吗?
Can you provide a stable reproduced minimum demo?

@wxrqforever
Copy link
Author

你可以提供一个稳定复现的最小demo吗?
Can you provide a stable reproduced minimum demo?

明白 我尽快提供 多谢

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug Category issues or prs related to bug.
Projects
None yet
Development

No branches or pull requests

3 participants