只是一个简单的问题,其中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环境中,具有事务语义和事务范围持久化上下文。
什么将打印到控制台?
答案 0 :(得分:4)
假设在调用同一实例和NESTED事务传播的方法时启用了事务语义: 它取决于持久化上下文的范围。
假设事务作用域持久化上下文:
black
将打印到控制台。汽车实例已分离,因为它是在只读事务之外获取的,并未合并到只读事务中。在分离的实例上调用setter是安全的(比如调用setColor("blue")
。
假设持久化上下文的扩展范围:
还会打印black
。来自@Transactional
如果
当被要求进行只读事务时,无法解释只读提示的事务管理器不会引发异常。
从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()
仍然只是一个简单的方法调用。