在查询方法上加 @Transactional(readOnly=true),不能单独证明工具无法写数据。验收时要分别观察事务提示、数据库强制机制和应用允许的操作。
前置:事务代理与事件、服务端工具授权。下面两组 Java 练习均为未运行的设计。
提示与强制机制
@Transactional(readOnly=true) 是交给实际事务子系统的提示(read-only hint,可供运行时优化),并不承诺写入尝试一定失败。不支持该提示的事务管理器可以忽略它。因此,把查询方法加上此注解,不能单独作为 Agent 工具没有写入能力的验收证据。Transactional API
DataSourceTransactionManager 提供 setEnforceReadOnly(boolean);在启用且事务定义为只读时,其默认连接准备实现执行 SET TRANSACTION READ ONLY,区别于普通 JDBC 只读提示。文档列出 Oracle、MySQL、Postgres 支持该语句,但项目仍须核对真实管理器、数据库及驱动行为。不能将某个管理器的配置扩展为所有 @Transactional 的保证。DataSourceTransactionManager API
练习一 比较两种事务配置
在一次性测试数据库和假商户表中,创建两个隔离配置,分别使用普通 DataSourceTransactionManager 与显式 setEnforceReadOnly(true) 的实例。用 TransactionTemplate.setReadOnly(true) 开启新事务,先 SELECT,再尝试对预置假商户 UPDATE。记录数据库、驱动及管理器版本、是否发出只读 SQL、异常和事务结束后数据;未被拒绝的测试写入显式回滚。普通提示组允许因驱动不同出现不同结果,不能预设它必定写成功;强制组则验收所选数据库与配置的实际拒写行为。不得在生产库做此实验,也不以测试注解自动回滚替代结果检查。
练习二 数据库之外的副作用
给同一查询服务注入可计数的外部副作用替身,在只读事务内调用替身,再主动抛出异常使数据库回滚。分别检查数据库与替身调用计数,展示事务数据库边界不自动覆盖其他系统。随后让 HTTP 与 Agent 工具两条入口执行相同的授权和允许操作检查,断言被拒请求未到达写方法或外部替身。这里检验的是应用边界,不能用“数据库拒绝 UPDATE”推导整个工具无副作用。
应用范围
默认代理模式仍需经过代理入口,参见事务注解指南。数据库拒绝 UPDATE 不能推出外部调用、消息发送等全部被阻止。按项目真实管理器、驱动、数据库及最小权限设计验收,不要仅为本例升级框架或直接替换生产事务管理器。
来源与版本
Spring Framework 7.0.10。资料原核查时间为 2026 年 10 月 29 日 06:04–06:05 JST,独立发布日期未标明。来源为上述 Transactional、DataSourceTransactionManager API 及事务注解指南;没有执行数据库写入或修改事务配置。