Spring Data CrudRepository 的保存抛出 InvocationTargetException

Posted

技术标签:

【中文标题】Spring Data CrudRepository 的保存抛出 InvocationTargetException【英文标题】:Spring Data CrudRepository's save throws InvocationTargetException 【发布时间】:2021-12-16 01:56:00 【问题描述】:

我整个周末都在尝试调试这段代码。我有一个 Spring RestController:

import com.tsakirogf.schedu.model.ContactMean;
import com.tsakirogf.schedu.model.DefaultContactMean;
import com.tsakirogf.schedu.model.human.Business;
import com.tsakirogf.schedu.services.BusinessService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import java.util.Optional;
import java.util.Set;

@RestController
@RequestMapping("api/v1/business/")
public class BusinessController

    @Autowired
    BusinessService businessService;

    @GetMapping(value = "businesss")
    Iterable<Business> list()
    
        Iterable<Business> retVal = businessService.findAll();
        return retVal;
    

    @RequestMapping(value = "business", method = RequestMethod.POST,  consumes = MediaType.APPLICATION_JSON_VALUE)
    Business create(@RequestBody Business business)
    
        CollectionOfContactMethods collectionOfContact = business.getContact();
        collectionOfContact.setBusiness(business);
        Set<ContactMean> contactMeanSet = collectionOfContact.getContactMeans();
        DefaultContactMean defaultContactMeanSet = collectionOfContact.getDefaultContactMean();
        defaultContactMeanSet.getCollectionOfContactMethodsDefault().setId(collectionOfContact.getId());
        for (ContactMean element : contactMeanSet)
        
            element.setCollectionOfContactMethods(collectionOfContact);
        
        collectionOfContact.setDefaultContactMean(defaultContactMeanSet);
        business.setContact(collectionOfContact);

        Business retval = businessService.save(business);
        return retval;
    

    @RequestMapping(value = "business/id",  method = RequestMethod.GET )
    Optional<Business> get(@PathVariable Long id)
    
        return businessService.findById(id);
    

还有服务:


public interface BusinessService extends CrudRepository<Business, Long>


这是模型:

@Table(name = "business")
public class Business

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

    @JsonProperty("name")
    private String name;

    @Embedded
    @JsonProperty("address")
    private Address address;

    @OneToMany(mappedBy = "business",
        cascade = CascadeType.ALL,
        fetch = FetchType.LAZY)
    @JsonProperty("operatives")
    @JsonIgnore
    Set<Professional> operatives;

    @OneToOne(mappedBy = "business",
        cascade = CascadeType.ALL,
        fetch = FetchType.LAZY,
        optional = false)
    @JsonBackReference
    @JsonProperty("contact_numbers")
    private CollectionOfContactMethods contact;

    public Business()
    
    

    // Getters and Setters

当我发送这样的 POST 请求时:

我从哪里得到以下内容

"时间戳": "2021-11-01T08:59:06.343+00:00", “状态”:500, "error": "内部服务器错误", “路径”:“/api/v1/business/business”

我调试并得到 InvocationTargetException,如下所示 这是控制器,就在 save() 之前似乎抛出:

这里有一个问题:

我发现 this article 在 *** 的 similar event 中发布,但我不认为在这种情况下会发生这种情况,因为我现在只有 H2 数据库。 这是 application.properties 文件:

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

我会很感激任何想法。感谢您的宝贵时间。

【问题讨论】:

可以包含stackstrace吗? 将是我的荣幸 您有一个id 字段,它没有分配给它的生成器。因此,您需要更改它或在保存之前手动将id 分配给对象。 耶稣。我怎么错过了? @M.Deinum 就是这样(@GeneratedValue(strategy = GenerationType.SEQUENCE)),请随时创建答案并明白这一点。你当之无愧。另外,我将保留这个问题,因为这个例外似乎没有什么误导性。 【参考方案1】:

如果您查看上一个屏幕截图,您会看到一条消息,指出有一个没有值的 id 字段。

在您的实体中,您的id 字段声明如下:

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

这表明休眠它不应该生成密钥或没有分配给数据库的密钥。这意味着您将需要手动设置id 的值。如果不这样做,您将遇到此异常。

现在我假设这是一个错误,并且您实际上想要一个序列或自动递增的 id 字段。为此添加 @GeneratedValue 注释以添加此行为。

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE))
@Column(name = "business_id", nullable = false)
private Long id;

这将指示 hibernate 在插入实体时使用序列生成id。如果您的数据库支持identity 列,您可能希望使用GenerationType.IDENTITY 而不是GenerationType.SEQUENCE

【讨论】:

以上是关于Spring Data CrudRepository 的保存抛出 InvocationTargetException的主要内容,如果未能解决你的问题,请参考以下文章

@Tailable(spring-data-reactive-mongodb) 等效于 spring-data-r2dbc

如何利用spring data mongodb 进行多条件查询

Spring Data 系列 Spring+JPA(spring-data-commons)

初探 spring data--- spring data 概述

spring-data-jpa 和 spring-boot-starter-data-jpa 的区别

无法将 Spring Data MongoDB + Spring Data JPA 与 Spring Boot 一起使用