Spring Boot与H2内存数据库间JSON数据和@Entity类的存取方案咨询
问题解答
1. INSERT语句正确性确认
你写的INSERT语句完全正确,H2数据库支持直接将标准JSON格式的字符串用单引号包裹后存入JSON类型字段,你使用JSON数组存储多桌台信息的写法符合语法要求。
2. 核心问题解决方案
这里提供两种实现方案,优先推荐JPA属性转换器方案,无需手动处理序列化/反序列化逻辑,代码更简洁:
方案1:使用JPA属性转换器(推荐)
步骤1:创建JSON序列化转换器
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.persistence.AttributeConverter; import jakarta.persistence.Converter; import java.util.List; @Converter(autoApply = false) public class BookTableListConverter implements AttributeConverter<List<BookTable>, String> { private final ObjectMapper objectMapper = new ObjectMapper(); @Override public String convertToDatabaseColumn(List<BookTable> bookTables) { try { return objectMapper.writeValueAsString(bookTables); } catch (Exception e) { throw new RuntimeException("JSON序列化失败", e); } } @Override public List<BookTable> convertToEntityAttribute(String s) { try { return objectMapper.readValue(s, new TypeReference<List<BookTable>>() {}); } catch (Exception e) { throw new RuntimeException("JSON反序列化失败", e); } } }
步骤2:修改Restaurant实体类
@Entity @Data @AllArgsConstructor @NoArgsConstructor @Table(name = "restaurant") public class Restaurant { @Id @Column(name="ID") @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; @Column(name="NAME") private String name; // 建议替换为java.time.LocalDate,避免旧Date类的线程安全问题 @Column(name="BOOKING_DATE") private Date bookingDate; @Column(name = "TABLES", columnDefinition = "json") @Convert(converter = BookTableListConverter.class) private List<BookTable> tables; // 直接用List存储,不需要String类型 }
步骤3:调整Service层代码
// 新增餐厅方法直接保存即可,转换器会自动处理JSON转换 public void AddNewRestaurant(Restaurant restaurant) { // 如果需要同时保存桌台到BOOKTABLE表,可以在这里遍历tables调用tableService.save批量保存 restaurantRepository.save(restaurant); } // 查询方法不需要额外修改,转换器会自动将JSON字段转为List<BookTable> public Restaurant getRestaurant(Long id) { return restaurantRepository.findById(id) .orElseThrow(() -> new RuntimeException("未找到对应餐厅")); // 替换为自定义业务异常更规范 }
方案2:手动序列化/反序列化(兼容旧代码)
如果你不想修改现有实体的String类型tables字段,可以直接在Service层手动处理转换:
POST存储逻辑
public void AddNewRestaurant(Restaurant restaurant, List<BookTable> tables) throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); // 将List序列化为JSON字符串存入tables字段 String tablesJson = objectMapper.writeValueAsString(tables); restaurant.setTables(tablesJson); restaurantRepository.save(restaurant); }
GET读取转换逻辑
// 单个查询转换 public List<BookTable> getTablesByRestaurantId(Long id) throws JsonProcessingException { Restaurant restaurant = restaurantRepository.findById(id).orElseThrow(); ObjectMapper objectMapper = new ObjectMapper(); return objectMapper.readValue(restaurant.getTables(), new TypeReference<List<BookTable>>() {}); } // 批量查询转换可以遍历列表逐个处理
额外优化建议
- 如果你的业务中BookTable和Restaurant是强关联关系,也可以考虑去掉Restaurant表的JSON字段,改用@OneToMany关联映射,直接关联BOOKTABLE表,更符合关系型数据库设计规范
- 建议给查询接口添加异常处理,当ID不存在时返回404状态码而非500
- ObjectMapper可以作为单例注入Spring容器,不要每次调用都新建对象,提升性能
内容的提问来源于stack exchange,提问作者Jasmira Richelle Fernandes
相关产品推荐
相关产品推荐

