What is the relationship between spring transactions, asynchrony, and circular dependencies?

Programmer Xiaohang 2021-02-23 16:46:36
relationship spring transactions asynchrony circular


Preface

There is a kind of circular dependency in circular dependency , It's self injection : Depend on yourself .

Self injection of transactions

stay Spring Self calling transaction failure , How did you solve it ? Some small partners suggest that they can inject themselves to solve the transaction failure .

The specific usage is as follows :

@Slf4j
@Service
public class OrderBizServiceImpl implements OrderBizService {
// Inject yourself
@Autowired
private OrderBizService orderBizService;
@Override
public void callBack() throws Exception {
// A series of logic
// Transaction operation is needed to update order and user amount
orderBizService.updateOrderStatusAndUserBalance();
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateOrderStatusAndUserBalance() throws Exception {
// Inside is transaction logic
}
}

Did you find something amazing , The transaction is in effect .

In fact, I put myself in here , It's actually a proxy object injected , Mediation , It is also the transaction of the proxy object of the call , So the transaction takes effect .

Spring Transaction failure reason : Transactions can only be applied to public It works in a way ; Transactions need to be called from outside ,Spring Self calls will fail ; Suggested transaction notes @Transactional It is usually added to the implementation class .

Asynchronous self injection

Find out @Transactional Annotations can be self injected to solve the problem of transaction invalidation , In some development , It's natural to think of @Async Can asynchrony also self inject to solve the problem of loop dependence .

NO, NO, NO……

The facts tell us that it's impossible !

Start with mistakes :

Throw the exception part doCreateBean

Start pushing up exposedObject == bean There's something wrong with this one .

That is to say, when it's asynchronous , Again, the data obtained from the L2 cache is not the same as the initial one .

Object earlySingletonReference = getSingleton(beanName, false);

Get it again from the L2 cache Bean

This time, we found that it was different, so we reported an error .

Let's start. Debug, According to the logic of circular dependency , Execute to populateBean when , Attribute assignment , Find yourself dependent , At this point, you create yourself .

perform singleton.getObject Method

getEarlyBeanReference

getBeanPostProcessors()

And at this point getEarlyBeanReference First judge InfrastructureAdvisorAutoProxyCreator true call wrapIfNecessary Determine whether to generate a proxy object , There is no proxy object generated here .

And then start performing asynchronous AsyncAnnotationBeanPostProcessor Judgment for false. So there is no asynchronous generation of proxy object logic .

So keep looking down

It's normal at this point

Enter into initializeBean The logic of , There's a part called applyBeanPostProcessorsAfterInitialization

Aspect partner search , So post the code keywords .IDEA Use ⌘ + Shift + F Search for .

applyBeanPostProcessorsAfterInitialization

Loop execution post processor :

It's found that the execution is complete AsyncAnnotationBeanPostProcessor This PostProcessor after , The object has been changed . This results in the second level cache and the current Bean Different .

That's why @Async Self calling cannot , Because the proxy modifies the object in the later initialization phase .

@Transactional Why can we ?

getEarlyBeanReference

getBeanPostProcessors()

First judge InfrastructureAdvisorAutoProxyCreator true Generate a proxy object .

Generate proxy objects

The processor of the transaction PersistenceExceptionTranslationPostProcessor It's not implemented .

continue Debug Focus on applyBeanPostProcessorsAfterInitialization

end of execution , Find out Bean No change .

summary

  • @Transactional: The proxy object is generated when the circular dependency is upgraded from the second level cache to the third level cache .
  • @Async: It's in the initialization phase (initializeBean) To generate proxy objects . then @Async It leads to the following judgment exposedObject == bean by false , To throw an exception .

Self injection

As you can see, there are two places in the diagram where BeanPostProcessor :

  1. stay singletonFactory.getObject when , If it is SmartInstantiationAwareBeanPostProcessor Subclasses of execute getEarlyBeanReference Method .
  2. stay initializeBean Of applyBeanPostProcessorsAfterInitialization Will perform all BeanPostProcessor Of postProcessAfterInitialization Methods .

There are other places where the post processor is executing , such as applyBeanPostProcessorsBeforeInitialization , It's just that we focus on these two things .

In both cases, it is possible to generate proxy objects , @Transactional Is in getEarlyBeanReference Proxy object generated at , So I'll judge later Bean Whether it is changed or not true, and @Async The proxy object is generated asynchronously later , So the judgment doesn't pass .

thus , Analysis complete , The error of , Welcome to correct

- <End /> -

This article is from WeChat official account. - Programmer Xiaohang (gh_liuzhihang) , author : Liu Zhihang

The source and reprint of the original text are detailed in the text , If there is any infringement , Please contact the yunjia_community@tencent.com Delete .

Original publication time : 2021-02-02

Participation of this paper Tencent cloud media sharing plan , You are welcome to join us , share .

版权声明
本文为[Programmer Xiaohang]所创,转载请带上原文链接,感谢
https://javamana.com/2021/02/20210223164213507Z.html

  1. J2EE
  2. Vue uses SDK to upload seven cows
  3. k8s-dns
  4. JavaScript mailbox verification - regular verification
  5. k8s-dashboard
  6. How many questions can you answer?
  7. Spring annotation -- transactional
  8. [k8s cluster] construction steps
  9. k8s-kubeadm
  10. k8s-etcd
  11. Using HashMap to improve search performance in Java
  12. There is no class problem when Maven publishes jar package
  13. JavaScriptBOM操作
  14. J2EE
  15. k8s-prometheus-memory
  16. k8s-prometheus disk
  17. k8s-prometheus
  18. JavaScript BOM operation
  19. k8s-prometheus-memory
  20. k8s-prometheus disk
  21. k8s-prometheus
  22. Linux Disk Command
  23. Linux FS
  24. 使用docker-compose &WordPress建站
  25. Linux Command
  26. This time, thoroughly grasp the depth of JavaScript copy
  27. Linux Disk Command
  28. Linux FS
  29. Using docker compose & WordPress to build a website
  30. Linux Command
  31. 摊牌了,我 HTTP 功底贼好!
  32. shiro 报 Submitted credentials for token
  33. It's a showdown. I'm good at it!
  34. Shiro submitted credentials for token
  35. Linux Stress test
  36. Linux Root Disk Extension
  37. Linux Stress test
  38. Linux Root Disk Extension
  39. Redis高级客户端Lettuce详解
  40. springboot学习-综合运用(一)
  41. 忘记云服务器上MySQL数据库的root密码时如何重置密码?
  42. Detailed explanation of lettuce, an advanced client of redis
  43. Springboot learning integrated application (1)
  44. Linux File Recover
  45. Linux-Security
  46. How to reset the password when you forget the root password of MySQL database on the cloud server?
  47. Linux File Recover
  48. Linux-Security
  49. LiteOS:盘点那些重要的数据结构
  50. Linux Memory
  51. Liteos: inventory those important data structures
  52. Linux Memory
  53. 手把手教你使用IDEA2020创建SpringBoot项目
  54. Hand in hand to teach you how to create a springboot project with idea2020
  55. spring boot 整合swagger2生成API文档
  56. Spring boot integrates swagger2 to generate API documents
  57. linux操作系统重启后 解决nginx的pid消失问题
  58. Solve the problem of nginx PID disappearing after Linux operating system restart
  59. JAVA版本号含义
  60. The meaning of java version number