答案不一定,和配置有关。
普通事务查询事务应该都会这么去配置
<tx:method name="save" propagation="REQUIRED" isolation="READ_COMMITTED" />
<tx:method name="query" propagation="SUPPORTS" read-only="true" />
为什么有的码友自信满满的说他配置了readOnly = true ,但是在方法里面执行了缺是正常的,无报错行为?经过本人的测试,也出现了无报错正常执行的过程,但是是有前提的。我们假设查询方法为queryUserById(Long id),保存的方法为saveUser(User user)。
- 直接调用查询 queryUserById(Long id),能够正常查询并返回所需要的信息;如果将方法体修改为inser语句,也可以正常插入用户信息,并不会报错。这是因为 SUPPORTS 的传播行为是,如果有事务就是用事务如果没有事务就不是用事务。显而易见,这种调用方法并没有开启事务也就不存在事务的readOnly属性了。
- 调用saveUser(User user)方法,方法内部调用queryUserById(Long id);这时候如果queryUserById(Long id)方法体修改为inser语句,则依然不会报错。原因是由于事务传播机制造成的,queryUserById所使用的事务不是自己的,而是由saveUser()创建的事务继承过来的,saveUser()的事务readOnly默认是false,也因此不会报错。
为什么有的人说报错,有的人说不可以呢?
场景1:
我们将其中一个配置信息修改为 <tx:method name="query" propagation="REQUIRED" read-only="true" /> 然后你再试试?日志上会有一段预期的error:
场景2:
我们将其中一个配置信息修改为 <tx:method name="save" propagation="REQUIRED" isolation="READ_COMMITTED" read-only="true"/>
同样会出现以上问题,但这是保存事务啊,read个毛线的only啊,你是不是傻?
小结
关于readOnly的解释,官方文档说明如下:
readOnly属性注释.png
意思如下(来自某度的翻译):
如果事务是有效只读的,则可以将其设置为真的布尔标记,允许在运行时进行相应的优化。默认值为假。这只是对实际事务子系统的提示;它不一定会导致写入访问尝试失败。无法解释只读提示的事务管理器在请求只读事务时不会引发异常,而是静默地忽略该提示。
另:本人的实验环境为 spring4.x + mybatis + mysql。不知道不同的环境会不会出现不同的现象,网上码友有在hibernate说报错,这个鄙人木有实验过。
至此为止,懂了?
网友评论