如何使用休眠更新实体

Posted

技术标签:

【中文标题】如何使用休眠更新实体【英文标题】:How to update entity using hibernate 【发布时间】:2016-12-20 05:10:26 【问题描述】:

我有实体用户:

@Entity
@Table(name = "entity_user")
@AttributeOverride(name = "id", column = @Column(name = "user_id"))
public class User extends BaseObject implements Serializable 

    /**
     * Login, unique
     */
    private String email;

    private String username;

    /**
     * Secret for signing-in
     */
    private String password;

    /**
     * Type of user
     */
    private UserType userType;

    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinTable(name = "view_user_to_requestSet", joinColumns = 
        @JoinColumn(name = "user_id"), inverseJoinColumns = 
        @JoinColumn(name = "requestSet_id"))
    private Set<RequestSet> setOfRequesSet = new HashSet<>();

    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinTable(name = "view_user_to_requestSetCreator", joinColumns = 
        @JoinColumn(name = "user_id"), inverseJoinColumns = 
        @JoinColumn(name = "requestSet_id"))
    private Set<RequestSet> setOfRequesSetCreator = new HashSet<>();

    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinTable(name = "view_user_to_userTask", joinColumns = 
        @JoinColumn(name = "user_id"), inverseJoinColumns = 
        @JoinColumn(name = "userTask_id"))
    private Set<UserTask> setOfUserTask = new HashSet<>();

    public User() 
    

    .
    .
..... GET AND SET

基础对象是: @MappedSuperclass 公共类 BaseObject

@Id
@GeneratedValue
@Column(name = "entity_id")
private Long id;

/**
 *
 * @return true if the entity hasn't been persisted yet
 */
@Transient
public boolean isNew() 
    return id == null;


public Long getId() 
    return id;


public void setId(Long id) 
    this.id = id;

问题是,当我尝试更新对象时,出现错误:

Exception in thread "Thread-15" org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [UK_5fa729oayn43ynq4v2y4d9qcn]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement

Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '5' for key 'UK_5fa729oayn43ynq4v2y4d9qcn'

对于我正在使用的更新实体:

@Transactional
public void save(User value)
   em.merge(value);

我不知道为什么会出现此错误,如何更新我的对象?感谢您的帮助。

编辑: 我更新:

User u = em.find(persistedType, id); //get user by ID
u.getSetOfRequesSet().add(requestSet); //add one otem to set
userDap.merge(u); //save

【问题讨论】:

这并没有定义您尝试更新对象的方式。你从哪里得到对象? em.find() ?询问?那么它是分离的吗?那么你在分离时更新一些字段? 是否有包含加载和更新用户的事务?如果不是,我相信实体会分离,因此 Hibernate 可能不再知道它与数据库中的实体相同。它是否适用于这样的事务,或者如果您在合并“保存”之前加载实体? 是否存在多个 ID 相同的 RequestSet? 是的。我想用 id 1 保存 requestSet 以获得更多 users 如果您只是进行查找然后进行更新,则无需进行“合并”,因为对象将被“管理”......假设所有这些都在一个事务中。什么是“请求集”?它是已经持久化的,还是一个新的对象? 【参考方案1】:

看起来您的更新重复了集合 (em.merge) 中的条目。 为防止重复,您应该明确合并集。执行以下操作。

    将方法合并添加到用户:

    protected User merge(User other) 
        // Just assign all data members(2 examples here)
        setEmail(other.getEmail());
        ....
        setSetOfRequesSet(other.getSetOfRequesSet());
        ...            
    
    

    准备一个更新的对象实例:

    User updated = em.find(persistedType, id); //get user by ID
    updated.getSetOfRequesSet().add(requestSet); //add one item to set
    

    更新现有的数据库实体:

    User existing = em.find(persistedType, id);
    existing.merge(updated);
    

更新后不需要调用 em.merge,因为保存只会在事务结束时完成。

你可以找到解释here。

【讨论】:

以上是关于如何使用休眠更新实体的主要内容,如果未能解决你的问题,请参考以下文章

即使在两者之间发生错误,休眠也会自动更新我的实体

如何使用休眠环境避免不必要的审计

如何在多对多关系上使用休眠和 JPA 删除孤立实体?

在休眠中使用继承时如何仅获取一种实体?

休眠保存或更新行为

何时以及如何使用休眠二级缓存?