【问题标题】:Spring transaction internalsSpring事务内部
【发布时间】:2011-12-23 21:20:55
【问题描述】:

情况如下:

  1. Method1 中有四种数据库更新方法。 Method1 使用 Spring 事务管理语义进行注释。

  2. Method2 中有一个数据库读取方法,它在 Method1 执行完所有数据库更新后调用。 Method2 也使用 Spring 事务语义注解。

  3. 有web请求进来,控制器拦截请求,调用method1,然后调用method2。

  4. 交易也被包裹在网络请求周围。

我有兴趣知道的是:

1.Spring如何知道在事务成功后提交数据库更新?是否有一些关于执行事务管理的 Spring 实现的参考?

2.由于我们有交易的层次结构: 围绕 web-request->Transaction with Propagation=RequestNew for Method1->Transaction with Propagation=Required for Method2,Spring如何进行事务管理以确保事务在正确的上下文中以正确的顺序执行?

简而言之,如果能够逐一了解 Spring 如何在其所有最重要的细节中执行事务管理,或者参考文档而不是简单地以 JTA 或其他一些为中心的解释,那将是很棒的首字母缩略词。

谢谢

【问题讨论】:

    标签: java spring transactions internals


    【解决方案1】:

    让我们做一些基本的陈述。

    1. 事务上下文是一种环境,其中一些特殊属性(数据库会话)可用于应用程序运行时,否则这些属性是不可用的。事务上下文通常用于确定事务的范围。
    2. Spring 使用 AOP Proxies 和 XML 元数据来实现声明式事务管理。
    3. 注解用于标记特定方法的事务传播行为。
    4. Spring 使用Interceptor Mechanism 将事务应用于方法。

    这里我重用了上面@stacker给出的例子

    MyClass{
    
        @Transactional
        public void sequence() {
          method1();
          method2();
        }
    
        @Transactional
        void method1() {
        }
    
        @Transactional(propagation=Propagation.REQUIRES_NEW)
        void method2() {
        }
    
    }
    

    您也可以使用 xml 配置实现相同的功能。让我们把它当作它的流行和广泛使用。

    部署时

    • Spring 框架检查 xml 配置文件(著名的applicationContext.xml)并根据配置扫描@Transactional 注释的代码(假设该配置被提及为基于注释)。
    • 此后,它为标记为事务的方法生成 AOP 代理。简单来说,这些代理只不过是相关方法的包装。
    • 在这些包装方法中,还根据配置(即事务传播)生成事务顾问代码之前和之后。
    • 现在,当调用这些包装器方法时,事务顾问会在实际方法调用之前和之后出现。 .
    • 在上面的例子中用伪代码表示相同

        ProxyMyClass{   
          MyClass myclass;
          .
          .
          .
          sequence(){
           //Transaction Advisor code (Typically begin/check for transaction)
           myclass.sequence();
           //Transaction Advisor code(Typically rollback/commit)
          }
          .
          .
          .
          }
      

    这就是 spring 管理事务的方式。不过有点过于简单化了。

    现在回答你的问题,

    . Spring 如何知道在事务成功后提交数据库更新?是否有一些关于执行事务管理的 Spring 实现的参考?

    每当您调用事务下的方法时,您实际上调用了一个代理,该代理首先执行事务顾问(它将开始事务),然后调用实际的业务方法,一旦完成,另一个事务顾问执行(取决于方式方法返回,将提交或回滚事务)。

    既然我们有一个事务的层次结构:围绕 web-request 的事务->Transaction with Propagation=RequestNew for Method1->Transaction with Propagation=Required for Method2,Spring 如何进行事务管理以确保事务以正确的顺序在正确的上下文中执行?

    在事务层次结构的情况下,spring 框架会相应地生成事务顾问检查。对于你提到的例子,

    • 对于方法 1 (RequestNew) 事务顾问代码(或事务建议)将始终创建一个新事务。
    • for method2(必需)事务顾问代码(或事务建议)将检查现有事务,如果存在则使用相同的事务,否则创建新事务。

    有一个image on the spring documentation page 很好地总结了这些方面。

    希望这会有所帮助。

    【讨论】:

    • 这是一个令人难以置信的解释。谢谢
    • 你能请教一下吗?说明上图中调用者是控制器还是 Web 请求?
    • @tintin,调用者是控制器还是其他任何东西都没有关系。最后,它将是从某个类到代理的方法调用。
    【解决方案2】:
    Controller
    @Transactional
    public void sequence() {
      method1();
      method2();
    }
    
    @Transactional
    void method1() {
    }
    
    @Transactional(propagation=Propagation.REQUIRES_NEW)
    void method2() {
    }
    

    默认传播是必需的(支持当前事务,如果不存在则创建一个新事务。)因此 m1 将使用在控制器中启动的事务。 m2 被注释为 REQUIRES_NEW (创建一个新事务,如果存在则暂停当前事务。)事务的顺序是您调用事务方法的顺序。

    Controller
    begin tx1
       |--------------------> m1 (uses tx1)
       |
       | begin tx2
       |--------------------> m2 (uses tx2)
       | commit tx2
    commit tx1
    

    【讨论】:

    • 在典型的 MVC 环境中,事务是否从控制器级别开始?还是从控制器调用的 @Transactional 注释开始服务?
    • @tintin 如果您有“低级”服务,您可能希望将它们组合到不同的事务中(用于不同的操作),因此您应该在控制器中启动事务。使用 Transactional 注释的方法加入现有事务(例如(在控制器中启动)
    【解决方案3】:

    你读过Spring documentation吗?基本上 AOP 用于管理事务。您还应该阅读AOP documentation。如果 AOP 文档还不够,我建议您仔细阅读代码。使用断点在调试模式下单步执行代码会很好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-15
      • 1970-01-01
      • 2013-04-11
      • 2016-11-10
      • 1970-01-01
      • 2014-07-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多