Spring@Transactional(readOnly=true)是否恢复属性



一个简单的问题,带有一个值为红色的Car实体持久化字段颜色:

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环境中,具有事务语义和事务范围的持久性上下文。

将打印到控制台的内容?

  • 红色
  • 蓝色
  • 黑色

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

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

假设持久性上下文的扩展范围:还打印CCD_ 3。来自@Transactional的javadoc

如果

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

来自JPA 2.0规范第2.4.1.2节派生恒等式的映射:

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

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

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

我相信您在Spring中已经陷入了AOP的陷阱。

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

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

它是这样的:

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

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

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

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

所以你知道答案。

此外,即使您设法通过代理调用,也不会改变情况:

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

这是因为传递给test1()Car实例是在test()周围的事务(即Hibernate会话)中检索的,无论您在test1()中做了什么更改,都不会对在test1()中单独创建的Hibernate会话执行任何操作(如果您使用REQUIRED_NEW传播)。您只是简单地更改传入对象的状态。因此,调用test1(c)仍然只是一个简单的方法调用。

最新更新