Spring Boot+MariaDB中JSON字段ZonedDateTime时区转换异常问题
Spring Boot + MariaDB 存储JSON字段时ZonedDateTime时区丢失问题
项目环境与代码实现
我正在开发一个基于Spring Boot和MariaDB的项目,需要将Student实体中的Exam属性以JSON格式存储到数据库中。相关代码和配置如下:
数据库表结构
CREATE TABLE IF NOT EXISTS student ( id bigint not null, exam json, first_name varchar(255), last_name varchar(255), primary key (id) ) engine=InnoDB;
Student实体类
使用JsonStringType将Exam属性映射为JSON字段:
@Data @NoArgsConstructor @AllArgsConstructor @Entity @TypeDefs({ @TypeDef(name = "json", typeClass = JsonStringType.class) }) public class Student implements Serializable { // 其他属性省略... @Column(columnDefinition = "LONGTEXT") @Type(type = "json") private Exam exam; }
Exam普通类
Exam并非JPA实体,只是包含ZonedDateTime类型属性的普通类:
@Data @NoArgsConstructor @AllArgsConstructor public class Exam implements Serializable { private ZonedDateTime startTime; private String code; }
Repository接口
@Repository public interface StudentRepository extends JpaRepository<Student, Long> { }
单元测试代码
测试数据生成方法
public Student createStudentEntity() { // 生成带当前时区(Europe/Paris)时间的Exam对象 Exam exam = new Exam(ZonedDateTime.now(), "math01"); Student student = new Student(); student.setExam(exam); // 其他属性赋值省略... return student; }
测试用例
@ActiveProfiles("test") @SpringBootTest class StudentTest { @Autowired StudentRepository studentRepo; @Test void test_save_student() { Student student = MyTestHelper.createStudentEntity(); studentRepo.save(student); // 断言失败,时区不匹配 Assertions.assertEquals(student, studentRepo.findById(student.getId()).get()); } }
问题现象
测试执行后断言失败,错误信息如下:
AssertionFailedError: expected: <Student(id=123,exam=Exam(startTime=2023-04-24T20:58:57.624489+03:00[Europe/Paris],...> but was: <Student(id=123,exam=Exam(startTime=2023-04-24T20:58:57.624489+03:00[UTC],...>
核心问题:
- 存入数据库前,
Exam.startTime的时区为Europe/Paris - 从数据库取出后,
startTime的时区变为UTC
已尝试的无效方案
给Exam.startTime添加Jackson的@JsonFormat注解指定时区:
@Data @NoArgsConstructor @AllArgsConstructor public class Exam implements Serializable { @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSSZ", timezone = "Europe/Paris") private ZonedDateTime startTime; private String code; }
但问题依旧,取出后的时区仍然是UTC。
内容的提问来源于stack exchange,提问作者user842225
相关产品推荐
相关产品推荐

