2015-02-09 66 views
0

运行Spring 4.1.4/Hibernate实体管理器4.1.8 /使用MySQL 5.6的Tomcat 8上的Spring JPA 2.1。保存新实体时在ManyToOne/OneToMany关系上创建的重复条目

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

Person类:

@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`) 
) 

现在的问题。

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

当服务返回到restlet时,会发生一个提交,但会触发第二次插入到widget表中。 (其对part_id +活动字段具有唯一约束)。我无法弄清楚,为了我的生活,为什么会发生这种情况。我已经尝试过几乎所有可能的组合,包括保存和冲洗人员,部件,都在之前冲洗,冲洗之后,默认属性。我觉得我现在很沮丧,以至于我看不到这个问题的核心。

事务在服务方法中开始,并在服务方法结束时结束。 (唯一的传播是默认的REQUIRED)。没有多重访问的担心,所以并发不是问题。

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

@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."); 
    } 
} 

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

+0

保存之前可以检查小部件或小部件的详细信息吗? – nayakam 2015-02-09 23:38:38

+0

这是什么? public void setWidgets(Set widgets) – 2015-02-10 10:15:21

+0

@Alan一个简单的转录错误。为了保护我的客户,我们更改了班级的名称;但显然我错过了一个。 :) – 2015-02-10 10:28:46

回答

0

我想我可以关闭这个问题。我发现了这个问题。

注意:在寻找代码中较低的问题时,请确保问题不是那么简单;例如意外地快速连续发出两个restlet调用,因为您意外调用了两次ajax javascript函数(添加到按钮)。

0

看起来像一个bug in hibernate。您可以尝试先保存孩子,然后再保存父母和孩子的关系。

相关问题