EntityManager merge()导致重复的行

时间:2016-07-03 19:10:19

标签: mysql hibernate jpa entitymanager

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

但是,有一次,似乎是第一次调用更新记录,它会在数据库中创建记录的副本,然后返回原始记录并对其进行更改。

我真的不知道为什么会这样。你会认为如果它创建了一个重复的记录,它会编辑那个,但是nope,在更新时会创建副本,放弃它,然后返回到第一个记录进行更改。

我正在思考它,因为我的实体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;
    }
}

1 个答案:

答案 0 :(得分:0)

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

您应该阅读有关equals and hasCode

的hi​​bernate文档