我在EntityManager.merge()上遇到了一些非常奇怪的行为。这是正在发生的事情。我有一个带有Spring MVC,Hibernate和JPA的REST API设置,用于从MySQL数据库中插入,更新和删除项目。插入和更新功能都使用EntityManager.merge(),并且它们都可以在99%的时间内正常工作。

但是,在某个时候,这似乎是第一个调用,以更新记录,它在数据库中创建了该记录的副本,然后返回到原始记录并对其进行了应有的更改。

我真的不知道为什么会这样。您会认为,如果它创建了重复记录,则可以编辑该记录,但是不行,更新时,它会创建重复记录,放弃它,然后返回到第一条记录进行更改。

我在想这是因为我在实体bean中具有哈希码和等于设置的方式,这可能是这样。尽管我没有发现它们有什么问题,因为我基于唯一键而不是ID来建立它们。

我的代码如下。任何关于正在发生的事情的想法都会有很大的帮助。

这是实体:

@Entity
@Table(name = "DAY_ITEM")
public class DayItem implements GtEntity, Serializable{
    private Long id;
    private String email;
    private String name;
    private BigDecimal amount;
    private Integer modId;
    private Integer fmOrder;
    private String modName;
    private Date daysDate;
    private String daysDateString;
    private Long foodId;
    private Long mealId;
    private FoodItem foodItem;
    private MealItem mealItem;
    private ArrayList<FoodItem> foodItems;
    private ArrayList<MealItem> mealItems;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long getId() {
        return id;
    }

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

    @Basic
    @Column(name = "EMAIL", nullable = false, length = 50)
    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Basic
    @Column(name = "NAME", nullable = true, length = 100)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Basic
    @Column(name = "AMOUNT", nullable = true)
    public BigDecimal getAmount() {
        return amount;
    }

    public void setAmount(BigDecimal amount) {
        this.amount = amount;
    }

    @Basic
    @Column(name = "MOD_ID", nullable = false)
    public Integer getModId() {
        return modId;
    }

    public void setModId(Integer modId) {
        this.modId = modId;
    }

    @Basic
    @Column(name = "FM_ORDER", nullable = false)
    public Integer getFmOrder() {
        return fmOrder;
    }

    public void setFmOrder(Integer fmOrder) {
        this.fmOrder = fmOrder;
    }

    @Basic
    @Column(name = "MOD_NAME", nullable = true, length = 50)
    public String getModName() {
        return modName;
    }

    public void setModName(String modName) {
        this.modName = modName;
    }

    @Basic
    @Column(name = "DAYS_DATE", nullable = false)
    public Date getDaysDate() {
        return daysDate;
    }

    public void setDaysDate(Date daysDate) {
        this.daysDate = daysDate;
    }

    @Transient
    public String getDaysDateString() {
        if(daysDateString == null) {
            DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
            return formatter.format(daysDate);
        }
        return daysDateString;
    }

    public void setDaysDateString(String daysDateString) {
        this.daysDateString = daysDateString;
    }

    @Basic
    @Column(name = "FOOD_ID", nullable = true)
    public Long getFoodId() {
        return foodId;
    }

    public void setFoodId(Long foodId) {
        this.foodId = foodId;
    }

    @Basic
    @Column(name = "MEAL_ID", nullable = true)
    public Long getMealId() {
        return mealId;
    }

    public void setMealId(Long mealId) {
        this.mealId = mealId;
    }

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "FOOD_ID", referencedColumnName = "ID",
            updatable = false, insertable = false)
    public FoodItem getFoodItem() {
        return foodItem;
    }

    public void setFoodItem(FoodItem foodItem) {
        this.foodItem = foodItem;
    }

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "MEAL_ID", referencedColumnName = "ID",
            updatable = false, insertable = false)
    public MealItem getMealItem() {
        return mealItem;
    }

    public void setMealItem(MealItem mealItem) {
        this.mealItem = mealItem;
    }

    @Transient
    public ArrayList<FoodItem> getFoodItems() {
        return foodItems;
    }

    public void setFoodItems(ArrayList<FoodItem> foodItems) {
        this.foodItems = foodItems;
    }

    @Transient
    public ArrayList<MealItem> getMealItems() {
        return mealItems;
    }

    public void setMealItems(ArrayList<MealItem> mealItems) {
        this.mealItems = mealItems;
    }

    public void makeDaysDate() throws ParseException{
        DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        this.daysDate = new Date(formatter.parse(this.daysDateString).getTime());
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof DayItem)) return false;

        DayItem dayItem = (DayItem) o;

        if (!getEmail().equals(dayItem.getEmail())) return false;
        if (!getModId().equals(dayItem.getModId())) return false;
        if (!getFmOrder().equals(dayItem.getFmOrder())) return false;
        if (!getDaysDateString().equals(dayItem.getDaysDateString())) return false;
        if (getFoodId() != null ? !getFoodId().equals(dayItem.getFoodId()) : dayItem.getFoodId() != null) return false;
        return getMealId() != null ? getMealId().equals(dayItem.getMealId()) : dayItem.getMealId() == null;

    }

    @Override
    public int hashCode() {
        int result = getEmail().hashCode();
        result = 31 * result + getModId().hashCode();
        result = 31 * result + getFmOrder().hashCode();
        result = 31 * result + getDaysDateString().hashCode();
        result = 31 * result + (getFoodId() != null ? getFoodId().hashCode() : 0);
        result = 31 * result + (getMealId() != null ? getMealId().hashCode() : 0);
        return result;
    }
}


这是执行初始创建的代码:

@Override
public List<DayItem> saveDayItem(DayItem item) throws Exception {
    EntityManager manager = entityManagerFactory.createEntityManager();
    EntityTransaction tx = manager.getTransaction();
    List<DayItem> results = null;
    try {
        tx.begin();
        manager.merge(item);
        manager.flush();
        manager.clear();
        results = findUserDay(item.getDaysDate(), item.getEmail(), manager);
        tx.commit();
    } catch (Exception e) {
        tx.rollback();
        throw e;
    } finally {
        manager.close();
        return results;
    }
}


这是进行更新的代码:

public <T extends GtEntity> T store(T entity) throws Exception {
    T managedEntity = null;
    EntityManager manager = entityManagerFactory.createEntityManager();
    EntityTransaction tx = manager.getTransaction();
    try{
        tx.begin();
        managedEntity = manager.merge(entity);
        tx.commit();
    }catch(RuntimeException e){
        tx.rollback();
        throw e;
    }finally {
        manager.close();
        return managedEntity;
    }
}

最佳答案

由于您实现了equalshasCode,因此Hibernate将使用这些方法来查找要更新的实体。假设分离对象已更改,equalshasCode将永远不会返回与附加实体相同的值,因此Hibernate将假定它是一个新实例。

您应该阅读有关equals and hasCode的休眠文档。

10-05 19:39