我们有一个使用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=?
您有什么建议吗?
谢谢
答案 0 :(得分:1)
我有一些建议:)
请注意Persistence Context
和entity lifecycle是transaction 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会删除日志中意外的删除和插入。
致谢