如何使用Spring Data读取JSON并写入MySQL数据库?
使用Spring Data将JSON持久化到MySQL的完整步骤
看来你已经有了基础的模型类,接下来咱们一步步把JSON数据存到MySQL里,全程用Spring Data JPA来实现,省心又高效。
1. 完善实体类的JPA映射
首先得给你的三个模型类加上JPA注解,处理好它们之间的一对多关联关系,这样Spring Data才能正确生成数据库表和关联约束。
Portal.java(主实体)
import jakarta.persistence.*; import java.util.ArrayList; import java.util.List; @Entity public class Portal { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String portalName; // 一对多关联Spaces,级联操作+孤儿移除 @OneToMany(mappedBy = "portal", cascade = CascadeType.ALL, orphanRemoval = true) private List<Spaces> spaces = new ArrayList<>(); // 构造方法(空参+带参)、getter/setter public Portal() {} public Portal(String portalName) { this.portalName = portalName; } // 辅助方法:添加Space时自动绑定关联关系 public void addSpace(Spaces space) { space.setPortal(this); this.spaces.add(space); } // getter和setter省略,自行补全即可 }
Spaces.java(关联Portal和Indicators)
import jakarta.persistence.*; import java.util.ArrayList; import java.util.List; @Entity public class Spaces { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String spaceName; // 多对一关联Portal @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "portal_id") // 数据库外键字段名 private Portal portal; // 一对多关联Indicators @OneToMany(mappedBy = "space", cascade = CascadeType.ALL, orphanRemoval = true) private List<Indicators> indicators = new ArrayList<>(); // 构造方法、getter/setter public Spaces() {} public Spaces(String spaceName) { this.spaceName = spaceName; } // 辅助方法:添加Indicator时自动绑定关联关系 public void addIndicator(Indicators indicator) { indicator.setSpace(this); this.indicators.add(indicator); } // getter和setter省略 }
Indicators.java(最底层实体)
import jakarta.persistence.*; @Entity public class Indicators { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String indicatorName; private String indicatorCounter; // 你的JSON里是字符串类型,这里保持一致 // 多对一关联Spaces @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "space_id") private Spaces space; // 构造方法、getter/setter public Indicators() {} public Indicators(String indicatorName, String indicatorCounter) { this.indicatorName = indicatorName; this.indicatorCounter = indicatorCounter; } // getter和setter省略 }
2. 创建Spring Data JPA Repository接口
每个实体对应一个Repository,Spring Data会自动实现CRUD方法,不用自己写SQL。
PortalRepository.java
import org.springframework.data.jpa.repository.JpaRepository; public interface PortalRepository extends JpaRepository<Portal, Long> { // 可自定义查询方法,比如根据portalName查找 Portal findByPortalName(String portalName); }
同理,你也可以给Spaces和Indicators创建对应的Repository(如果后续需要单独操作它们的话),比如SpacesRepository extends JpaRepository<Spaces, Long>。
3. 配置MySQL数据源
在application.properties(或application.yml)里配置数据库连接信息,确保Spring能连接到你的MySQL实例:
# 数据库连接 spring.datasource.url=jdbc:mysql://localhost:3306/your_db_name?useSSL=false&serverTimezone=UTC&characterEncoding=utf8 spring.datasource.username=your_db_username spring.datasource.password=your_db_password # JPA配置 spring.jpa.hibernate.ddl-auto=update # 自动更新表结构,生产环境建议用none或validate spring.jpa.show-sql=true # 控制台打印SQL,方便调试 spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect spring.jpa.properties.hibernate.format_sql=true # 格式化SQL输出
记得把your_db_name、your_db_username、your_db_password换成你自己的数据库信息。
4. 编写JSON解析与持久化服务
用Jackson(Spring Boot默认自带)把JSON字符串解析成实体对象,然后通过Repository保存到数据库。
PortalService.java
import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.stereotype.Service; import java.io.IOException; @Service public class PortalService { private final PortalRepository portalRepository; private final ObjectMapper objectMapper; // 构造注入(Spring 4.3+支持无需@Autowired) public PortalService(PortalRepository portalRepository, ObjectMapper objectMapper) { this.portalRepository = portalRepository; this.objectMapper = objectMapper; } public Portal savePortalFromJson(String jsonString) throws IOException { // 把JSON字符串转成Portal对象 Portal portal = objectMapper.readValue(jsonString, Portal.class); // 手动绑定关联关系(确保层级关联正确) portal.getSpaces().forEach(space -> { space.setPortal(portal); space.getIndicators().forEach(indicator -> indicator.setSpace(space)); }); // 保存到数据库,级联保存所有关联的Spaces和Indicators return portalRepository.save(portal); } }
如果你的JSON字段和实体属性名不一致,可以用@JsonProperty("json_field_name")注解来映射,比如实体属性叫portalName,JSON里是portal_name,就加@JsonProperty("portal_name")在属性上。
5. 测试功能
可以写一个接口或者测试类来验证功能是否正常。
示例Controller(接收JSON字符串并保存)
import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.io.IOException; @RestController @RequestMapping("/api/portal") public class PortalController { private final PortalService portalService; public PortalController(PortalService portalService) { this.portalService = portalService; } @PostMapping("/import") public ResponseEntity<Portal> importPortal(@RequestBody String jsonString) { try { Portal savedPortal = portalService.savePortalFromJson(jsonString); return ResponseEntity.ok(savedPortal); } catch (IOException e) { e.printStackTrace(); return ResponseEntity.badRequest().build(); } } }
JUnit测试类
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import static org.junit.jupiter.api.Assertions.*; @SpringBootTest public class PortalServiceTest { @Autowired private PortalService portalService; @Test public void testSaveFromJson() throws Exception { String json = "{ \"portalName\":\"office360\", \"spaces\": [ { \"spaceName\": \"Modèle d'Espace collaboratif\", \"indicators\": [ { \"indicatorName\": \"Created content\", \"indicatorCounter\": \"0\" }, { \"indicatorName\": \"answers reader\", \"indicatorCounter\": \"0\" } ] } ] }"; Portal savedPortal = portalService.savePortalFromJson(json); // 验证保存结果 assertNotNull(savedPortal.getId()); assertEquals("office360", savedPortal.getPortalName()); assertEquals(1, savedPortal.getSpaces().size()); assertEquals(2, savedPortal.getSpaces().get(0).getIndicators().size()); } }
一些注意事项
- 实体类命名:
Spaces建议改成Space(单数形式更符合JPA惯例),不过如果你已经用了这个名字也没关系,只是数据库表名会是spaces(默认小写)。 - 关联关系的懒加载:
FetchType.LAZY是默认值,能避免不必要的数据库查询,提升性能。 - 级联操作:
CascadeType.ALL意味着保存/删除Portal时,会自动处理关联的Spaces和Indicators,orphanRemoval = true会移除和Portal解除关联的Spaces。
内容的提问来源于stack exchange,提问作者amili
相关产品推荐
相关产品推荐

