spring kafkalistener在hibernate一对一单向Map中失败

pod7payv  于 2021-06-04  发布在  Kafka
关注(0)|答案(0)|浏览(235)

我使用spring数据jpa在hibernate中建立了一对一的关系模型。以下是我的模型:

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Data;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Nationalized;
import org.hibernate.annotations.Parameter;

@Data
@Entity
@Table(name = "parent")
public class Parent
{
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq-gen")
    @GenericGenerator(name = "seq-gen", strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator", parameters = { @Parameter(name = "sequence_name", value = "test_seq") })
    @Column(name = "id")
    private Long id;

    @Nationalized
    @Column(name = "Name", length = 50, nullable = false)
    private String name;
}
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.MapsId;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import lombok.Data;
import org.hibernate.annotations.Nationalized;

@Data
@Entity
@Table(name="child")
public class Child
{
    @Id
    private Long id;

    @OneToOne
    @MapsId
    private Parent parent;

    @Nationalized
    @Column(name = "name", nullable = false)
    private String name;
}

子表与父表具有外键关系,父表本身使用Map到子表的主键 @MapsId . 请注意,这是一种单向关系。
我使用的是spring数据jpa JpaRepository 将对象持久化到数据库中。

public interface ParentRepository extends JpaRepository<Parent, Long>{}
public interface ChildRepository extends JpaRepository<Child, Long>{}

在我的服务类中,我有一个简单的方法 Parent 对象,然后是 Child 对象。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class ServiceImpl
{
    @Autowired
    private ParentRepository parentRepository;

    @Autowired
    private ChildRepository childRepository;

    public void create()
    {
        Parent parent = new Parent();
        parent.setName("Parent");
        parent = parentRepository.save(parent);

        System.out.println(parent.getId());

        Child child = new Child();
        child.setName("Child");
        child.setParent(parent);
        childRepository.save(child);     // This line fails when using ControllerKafka
    }

}

我创建了一个restful控制器,它有一个 ServiceImpl 对象并调用服务类的相应方法。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ControllerRestful
{
    @Autowired
    private ServiceImpl service;

    @PostMapping(value = "/test")
    @ResponseStatus(HttpStatus.OK)
    public void create(@RequestBody UserDTO dto)
    {
        System.out.println(dto);
        service.create();
        System.out.println("Done");
    }
}

请注意,服务类独立于控制器。我在本地测试了这个端点,它将父对象和子对象持久化到数据库中。
现在,当我切换到基于kafka的控制器时,它在持久化时抛出一个错误。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.support.Acknowledgment;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;

@Controller
public class ControllerKafka
{
    @Autowired
    private ServiceImpl service;

    @KafkaListener(topics = "..", groupId = "..")
    @SendTo
    public void create(UserDTO dto, Acknowledgment acknowledgment)
    {
        service.create();
        System.out.println("Done");
        acknowledgment.acknowledge();
    }
}

错误日志:

org.springframework.kafka.listener.ListenerExecutionFailedException: Listener method 'public void ControllerKafka.create(UserDTO,org.springframework.kafka.support.Acknowledgment)' threw exception; 
nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: models.Parent;
nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: models.Parent; 
nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: models.Parent; 
nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: models.Parent
        at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.decorateException(KafkaMessageListenerContainer.java:1899) ~[spring-kafka-2.5.2.RELEASE.jar:2.5.2.RELEASE]
        at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeErrorHandler(KafkaMessageListenerContainer.java:1887) ~[spring-kafka-2.5.2.RELEASE.jar:2.5.2.RELEASE]
        at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeRecordListener(KafkaMessageListenerContainer.java:1792) ~[spring-kafka-2.5.2.RELEASE.jar:2.5.2.RELEASE]
        at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeWithRecords(KafkaMessageListenerContainer.java:1719) ~[spring-kafka-2.5.2.RELEASE.jar:2.5.2.RELEASE]
        at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeRecordListener(KafkaMessageListenerContainer.java:1617) ~[spring-kafka-2.5.2.RELEASE.jar:2.5.2.RELEASE]
        at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeListener(KafkaMessageListenerContainer.java:1348) ~[spring-kafka-2.5.2.RELEASE.jar:2.5.2.RELEASE]
        at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.pollAndInvoke(KafkaMessageListenerContainer.java:1064) ~[spring-kafka-2.5.2.RELEASE.jar:2.5.2.RELEASE]
        at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.run(KafkaMessageListenerContainer.java:972) ~[spring-kafka-2.5.2.RELEASE.jar:2.5.2.RELEASE]
        at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) ~[na:na]
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
        at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]

怎么可能 Child 内部对象 ServiceImpl 在下列情况下失败 ControllerKafka 但不是在 ControllerRestful ? 如果我移除 @MapsId 属性来自 Child 并具有不同的主键和外键 Child 实体,则在持久化时没有错误。

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题