java - 保存新实体时在 ManyToOne/OneToMany 关系上创建重复条目

标签 java mysql spring hibernate jpa

在带有 MySQL 5.6 的 Tomcat 8 上运行 Spring 4.1.4/Hibernate Entity Manager 4.1.8/Spring JPA 2.1。

我有两个实体。我们称它们为 Person 和 Widget。

人员类别:

@Entity(name = "person")
public class Person {
    @Id
    @GeneratedValue
    private Long id;

    //... Other properties omitted    
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "person", cascade = {CascadeType.ALL})
    private Set<Widget> widgets = new HashSet<>();

    public Set<Widget> getWidgets() {
        return widgets;
    }
    public void setWidgets(Set<Widget> widgets) {
        this.widgets = widgets;
    }
    public boolean addWidget(Widget widget) {
        return this.widgets.add(widget);
    }

    //...other getters/setters omitted
}

@Entity(name = "widget")
public class Widget {
    @Id
    @GeneratedValue()
    private Long id;

    @Column(name = "part_id")
    private String partId;
    //... Other properties omitted    
    @ManyToOne
    @JoinColumn(name = "person_id")
    private Person person;
    //...getters/setters omitted
}

我有两个数据库表设置如下:

CREATE TABLE `widget` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `person_id` bigint(20) NOT NULL,
  `active` tinyint(4) DEFAULT '1',
  `status_time` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
  PRIMARY KEY (`id`),
  UNIQUE KEY `widgets_ix1` (`part_id`,`active`),
  --some properties omitted
  KEY `widgets_fk1` (`person_id`),
  CONSTRAINT `person_fk1` FOREIGN KEY (`person_id`) REFERENCES `person` (`id`) ON DELETE NO ACTION ON UPDATE CASCADE
) --Some irrelevant details omitted

CREATE TABLE `person` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL,
--some properties omitted
  `status_time` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
  `create_time` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
  PRIMARY KEY (`id`)
)

现在讨论这个问题。

我有一个调用@Transactional 服务的reSTLet 调用。该服务创建一个新的小部件。设置一些属性并尝试通过 addWidget(...) 将其添加到 Person。然后我调用另一个只执行 saveAndFlush() 的服务方法。

当服务返回到 ReSTLet 时,会发生提交,但这会触发对小部件表的第二次插入。 (对part_id + Activity 字段有唯一的约束)。我一生都无法弄清楚为什么会发生这种情况。我已经尝试了保存和刷新人物、小部件、两者、之前刷新、之后刷新、默认属性的所有可能的组合。我想我现在很困惑,无法直视这个问题的核心。

事务在服务方法中开始,并在服务方法结束时结束。 (唯一的传播是默认的必需)。不用担心多重访问,因此并发不是问题。

这是围绕服务方法调用的逻辑。

@Override
@Transactional
public Message updateWidgetAdd(WidgetUpdateRequest message) {
    //Validation
    Person person = personService.findById(message.getPersonId());
    try {
        Widget widget = new Widget();
        widget.setPartId(message.getPartId().toLowerCase());
        widget.setActive(true);
        widget.setPerson(person);
        person.addWidget(widget);
        personService.save(person);
        return createSuccessPayload("id", widget.getId(), "partId", widget.getPartId());
    } catch(Exception e) {
        return createFailure("Uh oh.");
    }
}

我完全被难住了。欢迎任何建议/帮助!

最佳答案

看起来像 bug in hibernate 。你可以尝试先救 child ,再救亲子关系。

关于java - 保存新实体时在 ManyToOne/OneToMany 关系上创建重复条目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28420984/

相关文章:

java - Android如何多次调用一个方法并在它们之间有延迟

mysql - MySQL 中何时使用单引号、双引号和反引号

mysql - 为 postfix/dovecot 的 mysql 表中的所有用户设置别名

java - 启动 Tomcat 时 Web 模块没有从核心模块中找到类

Mac 中的 Java 1.6 没有 SwingWorker

java - 我如何在 Vaadin 7 中使用 dataProvider

java - maven basedir - 用前斜杠替换反斜杠

mysql - 服务器日期更改时触发

java - Paho MQTT 与 MQTT paho spring 集成

java - Spring 通用事件的事件监听器