使用@Transactional而非@Transactional(readOnly=true)执行只读查询会有问题吗?
@Transactional而非@Transactional(readOnly=true)处理只读数据库操作的潜在问题 嘿,这个问题问得很实在——不少开发者刚开始接触Spring事务时,都会忽略readOnly这个小属性,我来给你拆解下直接用普通@Transactional处理只读操作可能踩的坑:
数据库层面的性能冗余
多数主流数据库(比如MySQL InnoDB)对只读事务有专属优化:会跳过事务日志的写入流程,优先使用MVCC快照读来减少锁竞争,提升查询效率。如果不加readOnly=true,数据库会把它当成普通读写事务处理,额外的日志写入、锁机制都会带来不必要的性能损耗,高并发读场景下这种损耗会被明显放大。Spring事务生命周期做无用功
Spring处理readOnly=true的事务时,会跳过提交阶段的一系列冗余操作——比如不会创建回滚点、不会执行事务提交逻辑(毕竟只读事务没有修改数据,提交毫无意义)。而普通@Transactional会走完整的事务流程,哪怕你全程只有读操作,也会执行提交步骤,平白消耗系统资源。意外修改数据的风险
现在你的操作都是只读的,但后续代码维护时,万一有人不小心加了写操作(比如误更新某个字段),普通@Transactional会允许这个写操作提交;但如果用了readOnly=true,Spring会在事务提交前检测到写操作,直接抛出异常,帮你提前拦截这种意外修改,避免数据出错。ORM框架的优化机制失效
像Hibernate这类ORM框架,一旦识别到事务是只读的,会开启多项优化:比如跳过实体的脏检查(因为只读状态下不需要判断数据是否修改)、减少一级缓存的内存开销。如果用普通事务,这些优化都会失效,哪怕你没改数据,ORM也会做额外的检查,浪费性能。
当然,如果你的系统并发量低、读写操作不多,短期内可能看不出明显问题,但从代码规范、性能优化和风险防控的角度来说,给只读操作加上@Transactional(readOnly=true)是更稳妥的实践。
内容的提问来源于stack exchange,提问作者sam

