apache / incubator-seata

:fire: Seata is an easy-to-use, high-performance, open source distributed transaction solution.
https://seata.apache.org/
Apache License 2.0
25.25k stars 8.77k forks source link

@GlobalTransactional Annotation Not Working Due to Proxy Configuration #6562

Closed wanghongzhou closed 3 months ago

wanghongzhou commented 4 months ago

Issue Description:

Problem Summary:

I encountered an issue where the @GlobalTransactional annotation is not effective when a method in the same class calls another method annotated with @GlobalTransactional. The global transaction is not initiated in such cases. Below are the detailed steps and observations:

Steps to Reproduce:

  1. Class Setup:

    • I have a Service class with two methods, A and B.
    • Method A calls method B.
    • Method A does not have any annotations.
    • Method B is annotated with @GlobalTransactional.
  2. Observation:

    • The @GlobalTransactional annotation on method B is not triggering the global transaction.
    • This behavior is due to the fact that the call from method A to B bypasses the proxy object, thereby skipping the transactional proxy.
  3. Attempted Solution:

    • I attempted to use AopContext.currentProxy() to get the proxy object within method A.
  4. Error Encountered:

    • Using AopContext.currentProxy() resulted in an error.

Debugging Details:

Request:

Could you provide support for directly configuring the exposeProxy attribute? This would allow the AopContext.setCurrentProxy(proxy) method to be executed, thereby enabling the @GlobalTransactional annotation to function correctly in cases where a method within the same class calls another annotated method.

Additional Context:

Ensuring that the exposeProxy attribute can be configured would greatly enhance the usability of the @GlobalTransactional annotation, especially in complex service classes where internal method calls are common.

Thank you for your attention to this matter. I look forward to your response and a potential fix or workaround for this issue.

Bughue commented 4 months ago

This is the same as when you use spring's @Transactional annotation, so how did you solve the same problem with your @Transactional?

wanghongzhou commented 4 months ago

This is the same as when you use spring's @Transactional annotation, so how did you solve the same problem with your @Transactional?


After adding the @EnableAspectJAutoProxy(exposeProxy = true) annotation, I can obtain the proxy object for @Transactional through AopContext.currentProxy(). By using the proxy object, @Transactional becomes effective. However, this annotation does not work for @GlobalTransactional, because the proxy object for @GlobalTransactional is created by GlobalTransactionScanner.

I temporarily constructed a GlobalTransactionScanner myself, as shown below:

@Bean
@ConditionalOnMissingBean
@DependsOn({BEAN_NAME_SPRING_APPLICATION_CONTEXT_PROVIDER, BEAN_NAME_FAILURE_HANDLER})
public GlobalTransactionScanner globalTransactionScanner(SeataProperties seataProperties, FailureHandler failureHandler, ConfigurableListableBeanFactory beanFactory, @Autowired(required = false) List<ScannerChecker> scannerCheckers) {
    GlobalTransactionScanner.setBeanFactory(beanFactory);
    GlobalTransactionScanner.addScannerCheckers(EnhancedServiceLoader.loadAll(ScannerChecker.class));
    GlobalTransactionScanner.addScannerCheckers(scannerCheckers);
    GlobalTransactionScanner.addScannablePackages(seataProperties.getScanPackages());
    GlobalTransactionScanner.addScannerExcludeBeanNames(seataProperties.getExcludesForScanning());
    GlobalTransactionScanner.setAccessKey(seataProperties.getAccessKey());
    GlobalTransactionScanner.setSecretKey(seataProperties.getSecretKey());
    GlobalTransactionScanner globalTransactionScanner = new GlobalTransactionScanner(seataProperties.getApplicationId(), seataProperties.getTxServiceGroup(), failureHandler);
    globalTransactionScanner.setExposeProxy(true);
    return globalTransactionScanner;
}

Feel free to let me know if you need any further adjustments or additional details!

funky-eyes commented 4 months ago

Although this might be a question, it seems to stem from a lack of understanding about dynamic proxies. I don't think anyone would really use AopContext.currentProxy() to call another annotated method within the same instance.

funky-eyes commented 4 months ago

Since you've identified this issue, I believe it's worth submitting a PR to resolve it.

wanghongzhou commented 4 months ago

Since you've identified this issue, I believe it's worth submitting a PR to resolve it.


I believe the code changes required for this PR are minimal. We can add a new property private boolean exposeProxy = false; below the useJdkProxy property in the SeataProperties class. Then, we can modify the creation of globalTransactionScanner in the SeataAutoConfiguration class accordingly.

Unfortunately, I'm not very familiar with the PR process. Could you please check if there are other contributors who could help with creating this PR?

Thank you!


funky-eyes commented 4 months ago

我一向认为发现问题的人如果有能力解决该问题的话,我会鼓励和指导他去完成一个pr的提交,这是参与社区的一种体现。 你可以先fork seata仓库,然后在你fork的仓库中基于2.x分支新建一个分支,然后将你fork仓库的分支拉到本地,进行代码改造开发,当完成后,你可提交到你的fork仓库的分支中,然后回到seata仓库,点击pull requests,再选择new pull requests,选择你的fork仓库的对应分支,提交到seata仓库的2.x分支中即可。 标题可以optimize: 开头

I've always believed that if the person who identifies a problem has the ability to solve it, I would encourage and guide them to submit a PR, which is a manifestation of participating in the community. You can first fork the seata repository, then create a new branch based on the 2.x branch in your forked repository, then pull the branch of your forked repository to local, and carry out code modification and development. When finished, you can commit to the branch of your forked repository, then go back to the seata repository, click on pull requests, then choose new pull requests, select the corresponding branch of your forked repository, and submit to the 2.x branch of the seata repository. The title can start with "optimize: "

https://github.com/apache/incubator-seata/blob/2.x/CONTRIBUTING.md https://github.com/apache/incubator-seata/blob/2.x/CONTRIBUTING_CN.md