一个简单的问题,带有一个值为红色的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)
仍然只是一个简单的方法调用。