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

为何Spring Boot中Apps与App的JPA Repository无法保存数据?

Spring Boot中JPA无法保存从Roku API获取的Apps和App实体问题

我正在用Java Spring Boot开发一款基于Roku Dev Tools API的遥控器应用,TelevisionRepository能正常保存实体,但AppsRepository和AppRepository无法保存数据。怀疑和从Roku API(返回XML格式)解析对象属性有关。需求是调用http://{{rokuIPAddress}}:8060/query/apps获取指定电视的安装频道并保存到数据库。

控制器代码

// 获取电视应用列表
@GetMapping(path = "/get-apps/{name}")
public ResponseEntity<Apps> getApps(@PathVariable String name) {
    return appsService.getApps(name);
}

服务层代码

// 获取电视应用列表
public ResponseEntity<Apps> getApps(String name) {
    Television tele = televisionRepository.findByTelevisionName(name).orElseThrow(() -> new TelevisionNotFoundException());
    log.info(String.format("Requesting apps for %s via: http://%s:8060/query/apps", name, tele.getIpAddress()));
    ResponseEntity<Apps> responseEntity = this.restTemplate.getForEntity("http://" + tele.getIpAddress() + ":8060/query/apps", Apps.class);
    Apps apps = responseEntity.getBody();
    System.out.println(apps.toString());
    for (App app : apps.getApp()) {
        appRepository.save(app);
    }
    appsRepository.save(apps);

    return ResponseEntity.ok(apps);
}

实体类代码

App实体

@Entity
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "app")
public class App {

    @Id
    @XmlAttribute(name = "id")
    private String id;

    @XmlAttribute(name = "type")
    private String type;

    @XmlAttribute(name = "version")
    private String version;

    @ManyToOne(fetch = FetchType.LAZY)
    @JsonIgnore
    private Apps apps;
    
    // 构造方法、getter和setter
}

Apps实体

@Entity
@XmlRootElement(name = "apps")
@Table(name = "apps")
@XmlAccessorType(XmlAccessType.FIELD)
@JsonIgnoreProperties(ignoreUnknown = true)
public class Apps {

    @Id
    @GeneratedValue
    @Column(name = "id", nullable = false)
    private Long id;

    @OneToMany(mappedBy = "apps", cascade = CascadeType.REMOVE)
    @JacksonXmlElementWrapper(useWrapping = false)
    private List<App> app;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "television_id")
    @JsonIgnore
    private Television television;

    // 构造方法、getter和setter
}

Repository定义

AppRepository

public interface AppRepository extends JpaRepository<App, String> {
}

AppsRepository

public interface AppsRepository extends JpaRepository<Apps, Long> {
}

H2数据库配置

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true

问题原因及解决方法

  1. 关联关系未维护
    从Roku API解析得到的Apps和App对象之间没有建立双向关联,保存前需手动设置:

    Apps apps = responseEntity.getBody();
    // 建立双向关联
    if (apps.getApp() != null) {
        apps.getApp().forEach(app -> app.setApps(apps));
    }
    
  2. 级联配置缺失
    当前Apps的@OneToMany仅配置了删除级联,需添加保存/更新级联类型,这样保存Apps时会自动级联保存关联的App:

    @OneToMany(mappedBy = "apps", cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE})
    @JacksonXmlElementWrapper(useWrapping = false)
    private List<App> app;
    

    修改后无需循环调用appRepository.save(app),直接保存apps即可。

  3. Television关联未设置
    Apps实体关联了Television,但代码中未绑定对应电视对象,需添加:

    apps.setTelevision(tele);
    

    确保外键约束正常。

  4. 事务管理
    为服务层getApps方法添加@Transactional注解,避免事务边界问题导致数据未提交:

    @Transactional
    public ResponseEntity<Apps> getApps(String name) {
        // 原有代码逻辑
    }
    

内容的提问来源于stack exchange,提问作者Adriaan Veney

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 16:40:19