2

只是一个简单的问题,其 Car-entity 持久字段颜色为红色:

00  @Transactional public class MyBean{...
01    public void test(){
02        Car c = s.find(Car.class,1);
03        c.setColor("blue");
04        test1(c);
05        System.out.println(c.getColor());   
06    }
07    @Transactional(readOnly=true)
08    public void test1(Car c){
09        c.setName("black");
10    }
11  }

假设,我们在 Spring ORM TX-Transactional-Annotation 环境中,具有事务语义和事务范围的持久化上下文。

什么将打印到控制台?

  • 红色的
  • 蓝色的
  • 黑色的
4

2 回答 2

4

假设在调用同一实例的方法和 NESTED 事务传播时启用事务语义:这取决于持久性上下文的范围。

假设事务范围的持久性上下文: black打印到控制台。car 实例是分离的,因为它是在只读事务之外获取的,并且没有合并到只读事务中。在分离的实例上调用 setter 是安全的(就像调用setColor("blue").

假设持久性上下文的扩展范围: black也被打印。来自 javadoc@Transactional

如果

无法解释只读提示的事务管理器在请求只读事务时不会抛出异常。

并且来自 JPA 2.0 Spec Section 2.4.1.2 Mapping of Derived Identities:

对应于关系的嵌入 id 属性被提供者视为“只读”——也就是说,应用程序对它们的任何更新都不会传播到数据库。

但我不是 100% 确定,如果没有抛出异常。由于 color 属性不是嵌入的 id,因此行为可能会有所不同。

如果事务语义可通过代理获得,请参阅Adrian Shum 的答案

于 2012-10-10T08:20:55.363 回答
2

相信你在 Spring 中掉入了 AOP 的陷阱。

Spring 中的事务是通过 AOP 实现的,而 Spring 中的 AOP 是通过围绕实际目标的代理来实现的。

您已经为 MyBean 注释了 @Transactional。假设其他人正在调用 的实例MyBean.test(),它实际上并没有直接与该对象“交谈”。有一个代理,看起来完全一样MyBean,但它创建事务,然后调用实际的MyBean.test(),然后是提交/回滚。

它是这样的:

         test()                     test()
[Caller] ------->  [MyBean Proxy]  ------> [MyBean]

但是,当您调用test1()in时test(),这实际上意味着this.test1(),这意味着您正在直接调用 MyBean 实例:

          [MyBean Proxy]     [MyBean] <--
                                |       |  test1(c)
                                ---------

如果不通过MyBean Proxy(负责执行事务技巧),您的调用test1()实际上与事务无关。这只是一个简单的方法。

所以你知道答案了。

Moreover, even you manage to invoke through the proxy, it is not going to change the story:

          -> [MyBean Proxy]     [MyBean]
test1(c) |                         |
          -------------------------

That's because the instance of Car you passed to test1() is retrieved in the transaction (that means, Hibernate session) around test(), and whatever you change in test1(), you are not doing anything with the Hibernate session you created separately in test1() (if you use REQUIRED_NEW propagation). You are simply changing the state of the object passed in. Therefore, calling test1(c) is still nothing but a plain method call.

于 2012-10-10T10:06:34.887 回答