You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot JPA保存数据报Connection is read-only错误如何解决?

问题原因及解决方案

以下针对你遇到的两个独立问题分别说明:


1. Connection is read-only 写入报错问题

核心原因

出现该错误本质是当前执行写入操作的数据库连接被标记为只读状态,禁止执行增删改操作,结合你提供的代码,常见触发场景如下:

  • 多层事务注解叠加导致只读属性继承异常:你在Controller层、Service类、Service方法上都加了@Transactional注解,默认事务传播行为为REQUIRED,如果上层事务被标记为只读,下层事务会继承该属性,导致写入操作被拦截。
  • 事务注解属性配置错误:未显式给写入方法的事务注解设置readOnly = false,若全局事务配置默认给非指定前缀方法设置只读属性,会导致写入方法被误判为只读事务。
  • 数据库用户权限不足:Docker中部署的MySQL实例对应的业务用户只有查询权限,没有增删改权限。
  • 数据源连接池配置错误:配置文件中误将Hikari连接池的默认连接设置为只读模式。

解决方法

  • 统一事务控制逻辑:删除Controller层的@Transactional注解,事务控制只在Service层处理。将Service类上的通用事务注解显式标记为只读(适配查询方法),写入方法单独配置非只读事务,修改后Service代码参考:
@Service
@RequiredArgsConstructor
// 类上通用事务适配查询方法,默认只读
@Transactional(rollbackFor = Exception.class, readOnly = true)
public class UserService {
    private final UserRepository userRepository;
    public List<User> findAll() {
        return userRepository.findAll();
    }
    // 写入方法单独配置非只读事务
    @Transactional(rollbackFor = Exception.class, readOnly = false)
    public User saveToDb(User user) {
        return userRepository.save(user);
    }
}
  • 检查事务注解包路径:确保所有@Transactional使用的是org.springframework.transaction.annotation.Transactional包下的注解,不要误引入javax下的事务注解。
  • 验证数据库用户权限:进入Docker MySQL容器,登录数据库后执行命令SHOW GRANTS FOR '你的业务用户名'@'%';,确认用户拥有对应库的INSERT、UPDATE、DELETE权限,权限不足时执行授权:
GRANT INSERT,UPDATE,DELETE ON 你的库名.* TO '你的业务用户名'@'%';
FLUSH PRIVILEGES;
  • 检查数据源配置:确认配置文件中没有spring.datasource.hikari.read-only=true配置,如有删除该行即可。

2. 返回timestamp与当前时间差2小时问题

核心原因

该问题是时区不匹配导致的,你设置的serverTimezone=UTC是零时区标准时间,若你所在时区为东二区、或者Spring Boot JSON序列化时的时区、MySQL容器时区三者不统一,就会出现固定时间差。

解决方法

  • 修改数据源连接的时区参数:将serverTimezone=UTC替换为你所在时区的标准ID,比如国内用户替换为serverTimezone=Asia/Shanghai,东二区用户可替换为serverTimezone=Europe/Paris等对应时区。
  • 配置Spring Boot Jackson序列化时区:在application.properties中添加如下配置,统一JSON返回的时区:
spring.jackson.time-zone=你所在时区的标准ID(如Asia/Shanghai)
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
  • 统一Docker MySQL容器时区:启动MySQL容器时添加时区参数-e TZ=你所在时区的标准ID,如果容器已运行,可进入容器执行以下命令修改时区后重启容器:
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
echo Asia/Shanghai > /etc/timezone

内容的提问来源于stack exchange,提问作者Marco Cor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 08:45:07