Spring Data JPA读取MySQL实体遇READ ONLY事务异常求助
我来帮你排查这个问题,这个错误SQL Error: 1792, SQLState: 25006 Cannot execute statement in a READ ONLY transaction看起来有点矛盾——明明是执行select查询,却触发了只读事务不允许的写操作。下面是几个常见的原因和对应的解决办法:
1. 事务配置的只读属性冲突
如果你的查询方法标注了@Transactional(readOnly = true),虽然只读事务是用来优化查询的,但Hibernate在这种模式下会严格限制写操作。如果你的实体在查询过程中被意外标记为“脏数据”(比如不小心修改了某个字段,或者@Version字段的自动更新逻辑),Hibernate会尝试执行隐式的update语句,直接触发这个错误。
解决办法:
- 先尝试移除
@Transactional注解或者readOnly = true参数,看看是否还报错 - 如果必须使用只读事务,确保查询的实体在会话中是完全干净的,没有任何修改操作
2. 数据库连接池的只读设置
很多连接池(比如HikariCP)允许配置全局的只读属性,如果这个属性被设为true,整个MySQL会话会进入只读模式,此时任何写操作(包括Hibernate内部的缓存更新、元数据同步)都会被拦截报错,哪怕你只是执行select。
检查你的数据源配置,比如在application.yml里:
spring: datasource: hikari: read-only: false # 确保这个值是false
3. 实体类的生命周期回调触发写操作
如果你的实体类用了@PreLoad、@PostLoad这类生命周期注解,并且回调方法里有写数据库的逻辑(比如更新某个统计字段),那在查询加载实体时就会触发写操作,在只读事务里直接报错。
解决办法:
- 检查实体类的所有生命周期方法,移除里面的写操作逻辑
- 如果这些写操作是必须的,把它们移到非只读事务的方法中执行
4. 数据库层面的触发器问题
虽然这种情况比较少见,但如果你的查询目标表有在select时触发的触发器(比如某些审计场景下,查询时写入日志表),那在只读事务中执行查询就会触发写操作,导致报错。
解决办法:
- 登录MySQL,查看表的触发器定义:
SHOW TRIGGERS LIKE 'your_table_name'; - 修改或禁用这些会在查询时触发写操作的触发器
5. Hibernate自动DDL的干扰
如果你的Hibernate配置里hibernate.hbm2ddl.auto设置为update或create,应用运行时可能会自动执行DDL语句(比如修改表结构),如果此时刚好处于只读事务中,也会触发这个错误。
解决办法:
- 把
hibernate.hbm2ddl.auto设置为none或validate,避免运行时自动修改数据库结构
内容的提问来源于stack exchange,提问作者ScottM

