2009-09-25 2 views
0

TIMESTAMP 필드에 날짜/시간 값을 저장하고 레코드가 삽입 될 때 현재 시간 (UTC)으로 업데이트되는 사용자 정의 UserType이 있습니다. 또는 업데이트. 이 필드는 버전 관리 나 ID 용도로 사용되지 않습니다.Hibernate UserType nullSafeSet - insert/update 또는 select 호출시 알 수있는 방법

문제는 매우 잘 작동하지만 준비된 문이 만들어 질 때이 필드가 조건 중 하나 인 쿼리를 실행해야하는 경우 문제가 발생합니다. 사용자 정의 사용자 유형 nullSafeSet이 호출되어 값을 현재 시간으로 설정합니다. 그러면 쿼리가 항상 원하는 결과를 생성하지 않는 현재 시간으로 설정된 조건을 갖습니다.

삽입/업데이트 또는 선택에 대한 동작을 조정할 수 있도록 nullSafeSet이 호출되는 컨텍스트를 인식하도록 만들 수 있습니까? 아니면 이것을 할 다른 방법이 있을까요?

< 타임 스탬프 .../>을 사용해 보았지만 값을 UTC로 쓰지 않았습니다. (Backing 데이터베이스는 시간대를 잘 다루지 않는 Derby입니다.) replace (...) 메소드의 값을 업데이트하려고 시도했지만 엔티티가 세션에서 분리 된 경우에만 작동합니다 그리고 다시 돌아 왔어. 일부 코드의 경우 엔티티가 단일 세션 컨텍스트 내에서 검색되고 업데이트되어 필드가 업데이트되지 않습니다.

사용자 정의 사용자 유형에 UTC로 값을 쓰는 것이 가능하지만 일종의 생성기를 사용하여 삽입 및 업데이트시에만 현재 날짜/시간을 가져올 수 있습니까?

 
package example; 

import java.io.Serializable; 
import java.sql.PreparedStatement; 
import java.sql.ResultSet; 
import java.sql.SQLException; 
import java.sql.Timestamp; 
import java.util.Calendar; 
import java.util.Date; 
import java.util.GregorianCalendar; 
import java.util.Properties; 
import java.util.TimeZone; 

import org.hibernate.HibernateException; 
import org.hibernate.usertype.ParameterizedType; 
import org.hibernate.usertype.UserType; 

/** 
* The class DateTimestampUserType implements a Hibernate 
* UserType to allow the persistence of Date 
* instances as a TIMESTAMP in the database. 
* 
* All Date instances persisted are in UTC/GMT time. 
* 
* This UserType implementation also allows for a boolean parameter 
* 'updateToNow' specified as part of Hibernate configuration. This parameter 
* controls whether when a Date needs to be persisted it is updated 
* to the current time. This is useful for fields like TimeModified as it 
* requires no intervention by the calling code. 
*/ 
public class DateTimestampUserType implements UserType, ParameterizedType { 

    /* Constants */ 
    private static final String UTC_TZ = "GMT"; 

    /* Member Variables */ 
    private boolean m_updateToNow = false; 

    /* Methods */ 
    /* (non-Javadoc) 
    * @see org.hibernate.usertype.ParameterizedType#setParameterValues(java.util.Properties) 
    */ 
    public void setParameterValues(Properties parameters) { 
     if (parameters != null && parameters.containsKey("updateToNow")) { 
     m_updateToNow = Boolean.parseBoolean(parameters.getProperty("updateToNow")); 
     } 
    } 

    /* (non-Javadoc) 
    * @see org.hibernate.usertype.UserType#assemble(java.io.Serializable, java.lang.Object) 
    */ 
    public Object assemble(Serializable cached, Object owner) throws HibernateException { 
     return cached; 
    } 

    /* (non-Javadoc) 
    * @see org.hibernate.usertype.UserType#deepCopy(java.lang.Object) 
    */ 
    public Object deepCopy(Object object) throws HibernateException { 
     if (object == null) return null; 
     return new Date(((Date)object).getTime()); 
    } 

    /* (non-Javadoc) 
    * @see org.hibernate.usertype.UserType#disassemble(java.lang.Object) 
    */ 
    public Serializable disassemble(Object value) throws HibernateException { 
     return (Serializable) value; 
    } 

    /* (non-Javadoc) 
    * @see org.hibernate.usertype.UserType#equals(java.lang.Object, java.lang.Object) 
    */ 
    public boolean equals(Object x, Object y) throws HibernateException { 
     if (x == y) return true; 
     if (x == null || y == null) return false; 
     return x.equals(y); 
    } 

    /* (non-Javadoc) 
    * @see org.hibernate.usertype.UserType#hashCode(java.lang.Object) 
    */ 
    public int hashCode(Object object) throws HibernateException { 
     return object.hashCode(); 
    } 

    /* (non-Javadoc) 
    * @see org.hibernate.usertype.UserType#isMutable() 
    */ 
    public boolean isMutable() { 
     return true; 
    } 

    /* (non-Javadoc) 
    * @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet, java.lang.String[], java.lang.Object) 
    */ 
    public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner) throws HibernateException, SQLException { 
     Date result = null; 
     Calendar cal = new GregorianCalendar(TimeZone.getTimeZone(UTC_TZ)); 
     Timestamp timeStamp = resultSet.getTimestamp(names[0], cal); 

     result = new Date(timeStamp.getTime()); 

     return result; 
    } 

    /* (non-Javadoc) 
    * @see org.hibernate.usertype.UserType#nullSafeSet(java.sql.PreparedStatement, java.lang.Object, int) 
    */ 
    public void nullSafeSet(PreparedStatement statement, Object value, int index) throws HibernateException, SQLException { 
     if (m_updateToNow) { 
     value = new Date(); 
     } 

     Calendar cal = new GregorianCalendar(TimeZone.getTimeZone(UTC_TZ)); 
     Timestamp x = new Timestamp(((Date)value).getTime()); 
     statement.setTimestamp(index, x, cal); 
    } 

    /* (non-Javadoc) 
    * @see org.hibernate.usertype.UserType#replace(java.lang.Object, java.lang.Object, java.lang.Object) 
    */ 
    public Object replace(Object original, Object target, Object owner) throws HibernateException { 
     if (m_updateToNow) { 
     return new Date(); 
     } else { 
     return original; 
     } 
    } 

    /* (non-Javadoc) 
    * @see org.hibernate.usertype.UserType#returnedClass() 
    */ 
    public Class returnedClass() { 
     return Date.class; 
    } 

    /* (non-Javadoc) 
    * @see org.hibernate.usertype.UserType#sqlTypes() 
    */ 
    public int[] sqlTypes() { 
     return new int[] { java.sql.Types.TIMESTAMP }; 
    } 
} 

답변

1

nullSafeSet()가 호출됩니다 모두 실체가 업데이트/저장 될 때와 쿼리 매개 변수가 설정되어야 할 때.

"updateToNow"플래그에 문제가 있습니다. 해당 엔티티에 대한 매핑에서 true로 설정된 경우 항상이 현재 타임 스탬프로 값을 덮어 쓰게됩니다. 그것을 제거하면 괜찮을거야.

타임 스탬프를 항상 현재 (지정된 열에 대해)로 설정하는 경우 데이터베이스에서 그렇게하고 속성을 "생성 됨"으로 매핑하는 것이 좋습니다.

+0

네,이 방법을 사용하는 것처럼 보이지만 Derby를 사용하면 CURRENT_TIMESTAMP 또는 이와 유사한 필드를 사용해야 할 수 있습니다. Derby는 특정 시간대 (데이터베이스의 경우 UTC)의 CURRENT_TIMESTAMP를 지원하지 않으며 VM의 현재 시간대 (이 경우에는 UTC와 다를 수 있음)에 대해서만 지원합니다. –

+0

다른 옵션은 저장시 또는 적절한 수신기 (JPA/Hibernate Entity Manager를 사용하는 경우'@ PrePersist ')에서 DAO에서 수행하는 것입니다. – ChssPly76

+0

잠시 동안 DAO에서 업데이트를 완료했습니다. 나중에 더 나은 솔루션을 다시 방문 할 수 있습니다. Google에서 검색하는 동안 @PrePersist를 보았고 가능한 해결책 인 것처럼 보였습니다. 그러나 현재 JPA/HibernateEntityManager에서 주석을 사용하고 있지 않으며 현재 요구 사항을 갱신하는 데 오랜 시간이 걸릴 것입니다. –

관련 문제