Spring @Transactional(readOnly = true)还原属性?

时间:2012-10-10 08:09:40

标签: java spring hibernate transactional

只是一个简单的问题,其中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环境中,具有事务语义和事务范围持久化上下文。

什么将打印到控制台?

  • 红色
  • 蓝色

2 个答案:

答案 0 :(得分:4)

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

假设事务作用域持久化上下文: black将打印到控制台。汽车实例已分离,因为它是在只读事务之外获取的,并未合并到只读事务中。在分离的实例上调用setter是安全的(比如调用setColor("blue")

假设持久化上下文的扩展范围: 还会打印black。来自@Transactional

的javadoc

如果

  

当被要求进行只读事务时,无法解释只读提示的事务管理器不会引发异常。

从JPA 2.0 Spec Section 2.4.1.2派生身份的映射:

  

对应的嵌入式id属性   提供者将关系视为“只读” - 也就是说,对它们进行任何更新   应用程序的一部分不会传播到数据库。

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

如果通过代理可以获得事务语义,那么请参阅answer of Adrian Shum

答案 1 :(得分:2)

我相信你已经陷入了春季AOP陷阱。

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

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

这是这样的:

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

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

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

没有通过MyBean Proxy(负责执行交易技巧),您对test1()的调用实际上与Transaction无关。这只是一种简单的方法。

所以你知道答案。

此外,即使你设法通过代理调用,它也不会改变故事:

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

这是因为您传递给Car的{​​{1}}实例是在test1()周围的事务(即Hibernate会话)中检索的,以及test()中您更改的内容,你没有对你在test1()中单独创建的Hibernate会话做任何事情(如果你使用REQUIRED_NEW传播)。您只是更改传入的对象的状态。因此,调用test1()仍然只是一个简单的方法调用。