【问题标题】:Hibernate UserType nullSafeSet - how to know if called for insert/update or selectHibernate UserType nullSafeSet - 如何知道是否调用了插入/更新或选择
【发布时间】:2023-03-10 04:59:01
【问题描述】:

我有一个自定义 UserType,它在 TIMESTAMP 字段中存储日期/时间值,并在插入或更新记录时更新为“UTC”中的当前时间。 (此字段不用于版本控制或 id 目的。)

问题是这很好用,但是如果您需要在构建准备好的语句时运行此字段是条件之一的查询,则调用自定义用户类型 nullSafeSet 将值设置为当前时间,因此查询总是将该条件设置为当前时间,这不会产生所需的结果。

可以让 nullSafeSet 知道它被调用的上下文,以便它可以调整它的行为以进行插入/更新或选择。或者也许还有其他方法可以做到这一点?

我尝试过使用 ,但它没有以 UTC 格式写入值。 (后备数据库是 Derby,它本身不能很好地处理时区。)我也尝试过仅更新 replace(...) 方法中的值,但这仅在实体与会话分离时才有效然后带回来。从一些代码中,实体在单个会话上下文中被检索和更新,因此该字段不会被更新。

是否仍然可以让自定义用户类型以 UTC 格式写入值,但使用某种生成器仅在插入和更新时获取当前日期/时间?

包装示例; 导入 java.io.Serializable; 导入 java.sql.PreparedStatement; 导入java.sql.ResultSet; 导入java.sql.SQLException; 导入java.sql.Timestamp; 导入 java.util.Calendar; 导入 java.util.Date; 导入 java.util.GregorianCalendar; 导入 java.util.Properties; 导入 java.util.TimeZone; 导入 org.hibernate.HibernateException; 导入 org.hibernate.usertype.ParameterizedType; 导入 org.hibernate.usertype.UserType; /** * DateTimestampUserType 类实现了一个 Hibernate * UserType 允许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 的持久化需要持久化它已更新 * 到当前时间。这对于像 TimeModified 这样的字段很有用 * 不需要调用代码的干预。 */ 公共类 DateTimestampUserType 实现 UserType,ParameterizedType { /* 常量 */ 私有静态最终字符串 UTC_TZ = "GMT"; /* 成员变量 */ 私有布尔 m_updateToNow = false; /* 方法 */ /* (非 Javadoc) * @see org.hibernate.usertype.ParameterizedType#setParameterValues(java.util.Properties) */ 公共无效 setParameterValues(属性参数){ if (parameters != null && parameters.containsKey("updateToNow")) { m_updateToNow = Boolean.parseBoolean(parameters.getProperty("updateToNow")); } } /* (非 Javadoc) * @see org.hibernate.usertype.UserType#assemble(java.io.Serializable, java.lang.Object) */ 公共对象组装(可序列化缓存,对象所有者)抛出 HibernateException { 返回缓存; } /* (非 Javadoc) * @see org.hibernate.usertype.UserType#deepCopy(java.lang.Object) */ 公共对象 deepCopy(对象对象)抛出 HibernateException { 如果(对象==空)返回空; 返回新日期(((日期)对象).getTime()); } /* (非 Javadoc) * @see org.hibernate.usertype.UserType#disassemble(java.lang.Object) */ 公共可序列化反汇编(对象值)抛出 HibernateException { 返回(可序列化)值; } /* (非 Javadoc) * @see org.hibernate.usertype.UserType#equals(java.lang.Object, java.lang.Object) */ 公共布尔等于(对象 x,对象 y)抛出 HibernateException { 如果 (x == y) 返回真; if (x == null || y == null) 返回假; 返回 x.equals(y); } /* (非 Javadoc) * @see org.hibernate.usertype.UserType#hashCode(java.lang.Object) */ 公共 int hashCode(Object object) 抛出 HibernateException { 返回对象.hashCode(); } /* (非 Javadoc) * @see org.hibernate.usertype.UserType#isMutable() */ 公共布尔 isMutable() { 返回真; } /* (非 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 { 日期结果 = null; 日历 cal = new GregorianCalendar(TimeZone.getTimeZone(UTC_TZ)); 时间戳timeStamp = resultSet.getTimestamp(names[0], cal); 结果 = 新日期(timeStamp.getTime()); 返回结果; } /* (非 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 { 如果(m_updateToNow){ 值 = 新日期(); } 日历 cal = new GregorianCalendar(TimeZone.getTimeZone(UTC_TZ)); 时间戳 x = new Timestamp(((Date)value).getTime()); statement.setTimestamp(index, x, cal); } /* (非 Javadoc) * @see org.hibernate.usertype.UserType#replace(java.lang.Object, java.lang.Object, java.lang.Object) */ 公共对象替换(对象原始,对象目标,对象所有者)抛出 HibernateException { 如果(m_updateToNow){ 返回新日期(); } 别的 { 退回原件; } } /* (非 Javadoc) * @see org.hibernate.usertype.UserType#returnedClass() */ 公共类返回类(){ 返回日期.class; } /* (非 Javadoc) * @see org.hibernate.usertype.UserType#sqlTypes() */ 公共 int[] sqlTypes() { 返回新的 int[] { java.sql.Types.TIMESTAMP }; } }

【问题讨论】:

    标签: java hibernate


    【解决方案1】:

    nullSafeSet() 在保存/更新实体时以及必须设置查询参数时都被调用。

    您的问题在于“updateToNow”标志;如果在给定实体的映射中将其设置为 true,您将始终用当前时间戳覆盖值。删除它,你会没事的。

    如果您始终将时间戳设置为当前(对于给定列),请考虑在数据库中这样做,并将您的属性映射为“生成”。

    【讨论】:

    • 是的,这似乎是这样做的方法,但使用 Derby 您需要使用 CURRENT_TIMESTAMP 或类似的字段。 Derby 不支持特定时区(数据库为 UTC)的 CURRENT_TIMESTAMP,仅支持 VM 的当前时区,在我的情况下,该时区/必须不同于 UTC。
    • 好吧,您的另一个选择是在保存时在 DAO 中或在适当的侦听器中执行此操作(@PrePersist,如果您使用的是 JPA / Hibernate Entity Manager)。
    • 目前我刚刚在 DAO 中完成了更新。我以后也许可以重新考虑更好的解决方案。我在 Google 上搜索时确实看到了@PrePersist,这似乎是一个可能的解决方案,但我目前没有使用注释或 JPA / HibernateEntityManager,并且需要很长时间才能针对当前要求进行改造。
    • 您也可以在核心 Hibernate 中使用侦听器来执行此操作:docs.jboss.org/hibernate/stable/core/reference/en/html/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-31
    • 1970-01-01
    • 1970-01-01
    • 2014-11-24
    • 2016-11-25
    • 2016-07-18
    • 1970-01-01
    相关资源
    最近更新 更多