Hibernate 3.6에서 4.1.3 Final 로의 업그레이드를 완료했으며 처음에는 모든 것이 정상적으로 진행된 것 같습니다. 그러나 내 동료 중 한 명은 최근 한 시나리오에서 Hibernate 내에서 NullPointer를 가져 오는 시나리오를 테스트했습니다 (이 예외는 동일한 DB를 업그레이드하기 전에 throw되지 않았습니다). 엄청나게 이상한 시나리오입니다. 우리는 다음과 같은 블로그 게시물라는 엔티티를 가지고 있으며 (나는 또한 포함되었는지) 일부는 슈퍼 클래스를 매핑 확장 :Hibernate 4.1.3으로 업그레이드 한 후 NullPointerException 예외가 발생했습니다.
@Entity
@Table(name = "blog_post")
public class BlogPost extends CommunityModelObject implements HasFeedPost {
@Lob
private String title;
@Lob
private String content;
@Enumerated
@Column(nullable = false)
private CBlogPost.Status status = CBlogPost.Status.UNPUBLISHED;
// Reference to the feed post that indicates that this blog post has been published
@OneToOne
@JoinColumn(name = "feed_post_id")
private FeedPost feedPost;
@ManyToOne
@JoinColumn(name = "posted_by_employee_id")
private Employee postedBy;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public CBlogPost.Status getStatus() {
return status;
}
public void setStatus(CBlogPost.Status status) {
this.status = status;
}
@Override
public FeedPost getFeedPost() {
return feedPost;
}
@Override
public void setFeedPost(FeedPost feedPost) {
this.feedPost = feedPost;
}
public Employee getPostedBy() {
return postedBy;
}
public void setPostedBy(Employee postedBy) {
this.postedBy = postedBy;
}
}
@Filter(name = "tenantFilter", condition = "(tenant_id = :tenantId or tenant_id is null)")
@MappedSuperclass
public abstract class CommunityModelObject extends ModelObject {
@IndexedEmbedded(prefix = "tenant", indexNullAs = IndexedEmbedded.DEFAULT_NULL_TOKEN)
@ManyToOne
@JoinColumn(name = "tenant_id")
protected Tenant tenant;
public Tenant getTenant() {
return tenant;
}
public void setTenant(Tenant tenant) {
this.tenant = tenant;
}
/**
* If the Tenant is null then it can be accessed/viewed by the entire "community"/user base
*/
public boolean isCommunityObject() {
return tenant == null;
}
}
@MappedSuperclass
public abstract class ModelObject extends BaseModelObject {
@Id
@GeneratedValue
private Long id;
@Override
public long getId() {
return (id == null ? 0 : id);
}
public void setId(long id) {
this.id = (id == 0 ? null : id);
}
}
@MappedSuperclass
public abstract class BaseModelObject implements java.io.Serializable {
// This annotation ensures that a column is not associated with this member (simply omitting the @Column annotation is not enough since
// that annotation is completely optional)
@Transient
private boolean doNotAutoUpdateDateUpdated = false;
@Version
protected int version;
@Column(name = "date_created")
protected Date dateCreated;
@Column(name = "date_updated")
protected Date dateUpdated;
public abstract long getId();
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
public Date getDateCreated() {
return dateCreated;
}
public Date getDateUpdated() {
return dateUpdated;
}
/**
* This will set the dateUpdated to whatever is passed through and it will cause the auto update (pre-update) to NOT occur
*
* @param dateUpdated
*/
public void setDateUpdated(Date dateUpdated) {
doNotAutoUpdateDateUpdated = true;
this.dateUpdated = dateUpdated;
}
public void touch() {
// By setting date updated to null this triggers an update which results in onUpdate being called and the nett
// result is dateUpdated = new Date()
dateUpdated = null;
}
@PrePersist
protected void onCreate() {
dateCreated = new Date();
}
@PreUpdate
protected void onUpdate() {
if (!doNotAutoUpdateDateUpdated) {
dateUpdated = new Date();
}
}
@Override
public boolean equals(Object obj) {
long id = getId();
if (id == 0) {
return this == obj;
}
//Use Hibernate.getClass() because objects might be proxies
return obj != null &&
obj instanceof BaseModelObject &&
Hibernate.getClass(this) == Hibernate.getClass(obj) &&
getId() == ((BaseModelObject)obj).getId();
}
@Override
public int hashCode() {
Long id = getId();
return id == 0 ? super.hashCode() : id.intValue();
}
@Override
public String toString() {
return getClass().getSimpleName() + "-" + getId();
}
}
이상한 일이 일어나고 나는 몇 가지 시나리오에서 블로그 게시물을 쿼리 할 때. 나는 아래의 쿼리를 실행하는 경우, 예를 들어, 고립 그때는 잘 작동하지만 다음 다른 쿼리의 무리 사이를에서 실행하면 나는 아래의 예외를 얻을 :
select b from BlogPost b
java.lang.NullPointerException
at org.hibernate.event.internal.DefaultFlushEntityEventListener.isUpdateNecessary(DefaultFlushEntityEventListener.java:240)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:163)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:225)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99)
at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:55)
at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1153)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1208)
at org.hibernate.internal.QueryImpl.list(QueryImpl.java:101)
at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:256)
지금 키커 내가 가지고가는 경우이다 위에 나열된 모든 매핑 된 수퍼 클래스의 모든 필드를 직접 BlogPost에 넣고 BlogPost가 아무 것도 확장하지 않고 java.io.Serializable을 구현하면 모든 것이 완벽하게 작동합니다. 이것은 버그가 맵핑 된 수퍼 클래스 나 CommunityModelObject에 적용 할 하이버 네이트 필터와 관련이 있다고 생각하게한다.
해결 방법에 대한 의견이 있으십니까? 나는 그것이 Hibernate에서 새롭게 도입 된 버그라고 추측하고 있지만 잘못된 것일 수있다. 중요한 버그 수정을 위해 수행해야 할 최대 절전 모드 검색을 업그레이드하기 위해 최대한 업그레이드해야하므로 중요한 문제가 발생합니다.
는 또한 우리가 사용하고있는 DB가 우리의 비트 열을 처리하기 위해이 업그레이드를 수행 할 때 내가 쓴 다음과 같은 사용자 정의 방언과 MySQL의 대상이므로주의 :
public class MySQL5InnoDBDialectExt extends MySQL5InnoDBDialect {
private static final String BIT_STRING = "bit";
public MySQL5InnoDBDialectExt() {
super();
registerColumnType(Types.BOOLEAN, BIT_STRING);
}
}
감사합니다, 브렌트
참고로, 나는 이것을 Hibernate 포럼에도 게시했다 : https://forum.hibernate.org/viewtopic.php?f=1&t=1015428 – brent777