查找实体时休眠意外删除

时间:2018-09-13 08:22:42

标签: java hibernate jpa

我们有一个使用JPA和Hibernate在JBoss 6.4 GA上运行的Java ee应用程序,它具有以下实体:

@Entity
@SequenceGenerator(name = "sequence", sequenceName="SEQ_CAMPAIGNS_ID",allocationSize = 1)
@Table(name = "CAMPAIGN")
public class CampaignEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence")
@Column(name = "ID")
private Long id;

@Column(name = "NAME")
private String name;

@Column(name = "IS_ACTIVE", nullable = false)
private boolean active;

@Column(name = "START_DATE", nullable = false)
private Date startDate;

@Column(name = "END_DATE", nullable = false)
private Date endDate;

@Column(name = "LEGAL_ENTITY_ID", nullable = false)
private Integer legalEntityId;

@Column(name = "DEPARTMENT", nullable = false)
@Enumerated(value = EnumType.STRING)
private Department department;

@Column(name = "CATEGORY", nullable = false)
@Enumerated(value = EnumType.STRING)
private Category category;

@Embedded
CampaignConditionsEntity campaignConditions;

@OneToMany(cascade = CascadeType.ALL, mappedBy = "campaign", orphanRemoval = true)
@OrderBy
private List<CodeEntity> campaignCodes;

public CampaignEntity() {
}

以及以下CampaignConditionsEntity:

@Embeddable
public class CampaignConditionsEntity implements Serializable {

private static final String CAMPAIGN_ID = "CAMPAIGN_ID";

@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "CAMPAIGN_COND_TRIP_TYPE", joinColumns = @JoinColumn(name = CAMPAIGN_ID))
private Set<TripTypeConditionEntity> tripTypeConditions;

以及以下CodeEntity:

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@SequenceGenerator(name = "sequence", sequenceName = "SEQ_CODES_ID", allocationSize = 1)
public abstract class CodeEntity implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence")
@Column(name = "ID", nullable = false)
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "CAMPAIGN_ID")
private CampaignEntity campaign;

@OneToOne(mappedBy = "code", cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false, orphanRemoval = true)
private DiscountEntity discount;

@Column(name = "MAX_USAGES", nullable = false)
private Integer maxUsages;

@Column(name = "UNLIMITED_USAGES", nullable = false)
private boolean unlimitedUsages;

@Column(name = "NEGATIVE_SH", nullable = false)
private boolean negativeSH;

@Column(name = "UNIQUE_BUYER", nullable = false)
private boolean uniqueBuyer;

@Column(name = "START_DATE")
private Date startDate;

@Column(name = "END_DATE")
private Date endDate;

@Embedded
private CodeConditionsEntity codeConditions;

public CodeEntity() {
}

这是CodeConditionsEntity:

@Embeddable
public class CodeConditionsEntity implements Serializable {

private static final String CODE_ID = "CODE_ID";

@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "CODE_COND_TRIP_TYPE", joinColumns = @JoinColumn(name = CODE_ID))
private Set<TripTypeConditionEntity> tripTypeConditions;

@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "CODE_COND_CARRIERS", joinColumns = @JoinColumn(name = CODE_ID))
private Set<CarrierConditionEntity> carrierConditions;

这是CarrierConditionEntity:

@Embeddable
public class CarrierConditionEntity implements Serializable {

@Column(name = "CARRIER", nullable = false, length = 3)
private String carrierCode;

@Column(name = "IS_INCLUDED", nullable = false)
private boolean included;

问题在于,当我们执行的唯一操作是找到特定的广告系列实体时,我们在日志中发现意外删除。

在生产日志中,我们发现以下删除内容

Hibernate: delete from CODE_COND_CARRIERS where CODE_ID=? and CARRIER=? and IS_INCLUDED=? 

您有什么建议吗?

谢谢

2 个答案:

答案 0 :(得分:1)

我有一些建议:)

  • 请注意Persistence Contextentity lifecycletransaction scope(在JPA术语中的EntityManager实例,在Hibernate中是Session)是什么。 (工作单元)

  • 如果您不希望更改反映在数据库中,请不要更改实体状态,或者至少不要在更改实体之前将其分离。

  • 如果仅在相关工作单元中获取数据,则将事务标记为“ readOnly”。 (请注意,如果有许多“事务”方法加入同一物理事务,则该标志由周围的标志设置,并且不能被内部逻辑事务覆盖)。这样,EntityManager不会在事务结束时被刷新,并且挂起的更改也不会持久化到数据库中。

  • 您可以使用相关实体上的EntityListener跟踪触发意外删除的方法,并在{{1}中打印当前的strackTrace(new Throwable().printStackTrace() / log(new Throwable()) }方法

答案 1 :(得分:1)

我发现了问题所在:

问题在于实体没有实现equals()和hashcode()。还有一些具有@PostLoad的实体,该实体在从数据库加载后修改了该实体。然后在这种情况下,Hibernate会改变那些没有等号和哈希码的实体,然后将其全部删除,然后再次插入数据库中(在查询之前具有相同的实体) 添加equals和hashcode方法并删除postload会删除日志中意外的删除和插入。

致谢

相关问题